diff --git a/.github/ISSUE_TEMPLATE/release.md b/.github/ISSUE_TEMPLATE/release.md index 83701f14..bbe12160 100644 --- a/.github/ISSUE_TEMPLATE/release.md +++ b/.github/ISSUE_TEMPLATE/release.md @@ -1,6 +1,6 @@ --- -name: [SCT] Release checklist -about: Used by the Spec Core Team to create a new release. +name: '[SCT] Release checklist' +about: 'Used by the Spec Core Team to create a new release.' title: 'Matrix 1.X' labels: 'release-blocker' assignees: '' @@ -16,19 +16,22 @@ Previous release: Preflight checklist ([release steps](https://github.com/matrix-org/matrix-spec/blob/main/meta/releasing.md)): -* [ ] Blog post written -* [ ] Check for release blockers that may have been missed -* [ ] Review/fix the changelog +* [ ] Pin this issue to the repo. +* [ ] Ensure the social media account holders are available for the release day. +* [ ] Blog post written. +* [ ] Check for release blockers that may have been missed. +* [ ] Review/fix the changelog. Release checklist ([release steps](https://github.com/matrix-org/matrix-spec/blob/main/meta/releasing.md)): -* [ ] Branch stuffs -* [ ] Github release artifact -* [ ] Published to spec.matrix.org -* [ ] All links work -* [ ] Publish blog post -* [ ] Announce in #matrix-spec, client developers, HS developers, SCT office, and other rooms as warranted -* [ ] Post to Twitter/Mastodon -* [ ] Close this issue +* [ ] Branch stuffs. +* [ ] Github release artifact. +* [ ] Published to spec.matrix.org. +* [ ] All links work. +* [ ] Publish blog post. +* [ ] Announce in #matrix-spec, client developers, HS developers, SCT office, and other rooms as warranted. +* [ ] Post to Twitter/Mastodon. +* [ ] Close this issue. +* [ ] Unpin this issue from the repo. Known release blockers: * [ ] diff --git a/.github/_typos.toml b/.github/_typos.toml index e48ab53c..3cdecaa3 100644 --- a/.github/_typos.toml +++ b/.github/_typos.toml @@ -10,3 +10,4 @@ au1ba7o = "au1ba7o" [default.extend-words] Appy = "Appy" fo = "fo" +Iy = "Iy" diff --git a/.github/PULL_REQUEST_TEMPLATE/spec-change.md b/.github/pull_request_template.md similarity index 74% rename from .github/PULL_REQUEST_TEMPLATE/spec-change.md rename to .github/pull_request_template.md index 362c6862..0f4d5ccc 100644 --- a/.github/PULL_REQUEST_TEMPLATE/spec-change.md +++ b/.github/pull_request_template.md @@ -1,11 +1,3 @@ ---- -name: Spec clarification/not a proposal -about: A change that's not a spec proposal, such as a clarification to the spec itself. -title: '' -labels: '' -assignees: '' - ---- ### Pull Request Checklist diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 083d6831..694962d1 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -10,7 +10,7 @@ jobs: if: github.event_name == 'pull_request' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 - run: scripts/check-newsfragments diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d836b100..25a2fb68 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,4 +1,8 @@ name: "Spec" + +env: + HUGO_VERSION: 0.139.0 + on: push: branches: @@ -18,23 +22,23 @@ jobs: runs-on: ubuntu-latest steps: - name: "📥 Source checkout" - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: "➕ Setup Node" - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: - node-version: '14' + node-version: '20' - name: "🔎 Run validator" run: | npx @redocly/cli@latest lint data/api/*/*.yaml - check-examples: + check-event-examples: name: "🔎 Check Event schema examples" runs-on: ubuntu-latest steps: - name: "📥 Source checkout" - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: "➕ Setup Python" - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.9' cache: 'pip' @@ -45,7 +49,45 @@ jobs: - name: "🔎 Run validator" run: | python scripts/check-event-schema-examples.py - + + check-openapi-examples: + name: "🔎 Check OpenAPI definitions examples" + runs-on: ubuntu-latest + steps: + - name: "📥 Source checkout" + uses: actions/checkout@v4 + - name: "➕ Setup Python" + uses: actions/setup-python@v5 + 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-openapi-sources.py + + check-schemas-examples: + name: "🔎 Check JSON Schemas inline examples" + runs-on: ubuntu-latest + steps: + - name: "📥 Source checkout" + uses: actions/checkout@v4 + - name: "➕ Setup Python" + uses: actions/setup-python@v5 + 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: name: "⚙️ Calculate baseURL for later jobs" runs-on: ubuntu-latest @@ -61,11 +103,11 @@ jobs: # the asterisk matching behaviour, not the literal string. run: | if [ "${GITHUB_EVENT_NAME}" == "pull_request" ]; then - echo ::set-output name=baseURL::/ + echo "baseURL=/" >> "$GITHUB_OUTPUT" elif [[ "${GITHUB_REF}" == refs/tags/* ]]; then - echo ::set-output name=baseURL::"/${GITHUB_REF/refs\/tags\//}" + echo "baseURL=/${GITHUB_REF/refs\/tags\//}" >> "$GITHUB_OUTPUT" else - echo ::set-output name=baseURL::/unstable + echo "baseURL=/unstable" >> "$GITHUB_OUTPUT" fi build-openapi: @@ -74,9 +116,9 @@ jobs: needs: [calculate-baseurl] steps: - name: "📥 Source checkout" - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: "➕ Setup Python" - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.9' cache: 'pip' @@ -92,24 +134,29 @@ jobs: export RELEASE="unstable" fi # 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 }}" \ --api application-service \ -r "$RELEASE" \ -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 }}" \ --api client-server \ -r "$RELEASE" \ -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 }}" \ --api push-gateway \ -r "$RELEASE" \ -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 - name: "📤 Artifact upload" - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: openapi-artifact path: openapi.tar.gz @@ -121,18 +168,20 @@ jobs: runs-on: ubuntu-latest steps: - name: "📥 Source checkout" - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: "➕ Setup Python" - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 + with: + python-version: '3.9' - name: "➕ Install towncrier" run: "pip install 'towncrier'" - name: "Generate changelog" run: ./scripts/generate-changelog.sh vUNSTABLE - name: "📤 Artifact upload" - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: changelog-artifact - path: content/changelog/vUNSTABLE.md + path: content/changelog/unstable.md build-spec: name: "📖 Build the spec" @@ -142,23 +191,23 @@ jobs: if: ${{ always() }} steps: - name: "➕ Setup Node" - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: - node-version: '14' + node-version: '20' - name: "➕ Setup Hugo" - uses: peaceiris/actions-hugo@c03b5dbed22245418539b65eb9a3b1d5fdd9a0a6 + uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3.0.0 with: - hugo-version: '0.113.0' + hugo-version: ${{ env.HUGO_VERSION }} extended: true - name: "📥 Source checkout" - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: "⚙️ npm" run: | npm i npm run get-proposals - name: "📥 Download generated changelog" if: "needs.generate-changelog.result == 'success'" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: changelog-artifact path: content/changelog @@ -169,7 +218,7 @@ jobs: # https://spec.matrix.org/latest/client-server-api/api.json # Works for /unstable/ and /v1.1/ as well. - name: "📥 Spec definition download" - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: openapi-artifact - name: "📝 Unpack the OpenAPI definitions in the right location" @@ -179,7 +228,7 @@ jobs: - name: "📦 Tarball creation" run: tar -czf spec.tar.gz spec - name: "📤 Artifact upload" - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: spec-artifact path: spec.tar.gz @@ -190,10 +239,10 @@ jobs: needs: [calculate-baseurl, build-spec] steps: - name: "📥 Source checkout" - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: "📥 Fetch built spec" - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: spec-artifact @@ -210,7 +259,7 @@ jobs: - name: "Run htmltest" uses: wjdp/htmltest-action@master with: - config: .htmltest.yaml + config: .htmltest.yml build-historical-spec: name: "📖 Build the historical backup spec" @@ -219,16 +268,16 @@ jobs: if: ${{ startsWith(github.ref, 'refs/tags/') }} steps: - name: "➕ Setup Node" - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: - node-version: '14' + node-version: '20' - name: "➕ Setup Hugo" - uses: peaceiris/actions-hugo@c03b5dbed22245418539b65eb9a3b1d5fdd9a0a6 + uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3.0.0 with: - hugo-version: '0.93.3' + hugo-version: ${{ env.HUGO_VERSION }} extended: true - name: "📥 Source checkout" - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: "⚙️ npm" run: | npm i @@ -240,7 +289,7 @@ jobs: hugo --config config.toml,historical.toml --baseURL "/${GITHUB_REF/refs\/tags\//}" -d "spec" - name: "📥 Spec definition download" - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: openapi-artifact - name: "📝 Unpack the OpenAPI definitions in the right location" @@ -250,7 +299,7 @@ jobs: - name: "📦 Tarball creation" run: tar -czf spec-historical.tar.gz spec - name: "📤 Artifact upload" - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: spec-historical-artifact path: spec-historical.tar.gz diff --git a/.github/workflows/netlify.yaml b/.github/workflows/netlify.yaml index 83b6bec5..7c59f64c 100644 --- a/.github/workflows/netlify.yaml +++ b/.github/workflows/netlify.yaml @@ -25,17 +25,20 @@ jobs: id: readctx # we need to find the PR number that corresponds to the branch, which we do by # searching the GH API + env: + OWNER_LOGIN: ${{ github.event.workflow_run.head_repository.owner.login }} + HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} run: | - head_branch='${{github.event.workflow_run.head_repository.owner.login}}:${{github.event.workflow_run.head_branch}}' + head_branch="${OWNER_LOGIN}:${HEAD_BRANCH}" echo "head branch: $head_branch" pulls_uri="https://api.github.com/repos/${{ github.repository }}/pulls?head=$(jq -Rr '@uri' <<<$head_branch)" pr_number=$(curl -H 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' "$pulls_uri" | jq -r '.[] | .number') echo "PR number: $pr_number" - echo "::set-output name=prnumber::$pr_number" + echo "prnumber=$pr_number" >> "$GITHUB_OUTPUT" - name: '📥 Download artifact' - uses: dawidd6/action-download-artifact@af92a8455a59214b7b932932f2662fdefbd78126 # v2.15.0 + uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4 with: workflow: main.yaml run_id: ${{ github.event.workflow_run.id }} @@ -46,8 +49,7 @@ jobs: - name: "📤 Deploy to Netlify" id: netlify - # v1.2.2 - uses: nwtgck/actions-netlify@f517512ae75beec8896aa7b027c1c72f01816200 + uses: nwtgck/actions-netlify@4cbaf4c08f1a7bfa537d6113472ef4424e4eb654 # v3.0.0 with: publish-dir: spec deploy-message: "Deploy from GitHub Actions" diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..a53fe59a --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,42 @@ +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@v4 + with: + cache: "yarn" + cache-dependency-path: packages/npm/yarn.lock + registry-url: "https://registry.npmjs.org" + + - name: 🔨 Install dependencies + run: "yarn install --frozen-lockfile" + + # We bump the package.json version to git, we just need it for publish to do the right thing + - name: 🎖 Bump package.json version + run: "yarn version --new-version ${VERSION#v} --no-git-tag-version" + env: + VERSION: ${{ github.event.release.tag_name }}.0 + + - name: 🚀 Publish to npm + id: npm-publish + uses: JS-DevTools/npm-publish@19c28f1ef146469e409470805ea4279d47c3d35c # v3.1.1 + with: + token: ${{ secrets.NPM_TOKEN }} + package: packages/npm + access: public + ignore-scripts: false diff --git a/.github/workflows/spell-check.yaml b/.github/workflows/spell-check.yaml index d0b4a40e..541f7f93 100644 --- a/.github/workflows/spell-check.yaml +++ b/.github/workflows/spell-check.yaml @@ -11,9 +11,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Actions Repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Check spelling of proposals - uses: crate-ci/typos@9be36f97fdbe645ee9a12449fb13aca856c2516a + uses: crate-ci/typos@f2c1f08a7b3c1b96050cb786baaa2a94797bdb7d # v1.20.10 with: - config: ${{github.workspace}}/.github/_typos.toml \ No newline at end of file + config: ${{github.workspace}}/.github/_typos.toml diff --git a/.gitignore b/.gitignore index c1a34c50..23fd5b4a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ node_modules /data/msc /env* /resources -/scripts/swagger +/scripts/openapi /scripts/tmp /hugo-config.toml /public @@ -14,3 +14,4 @@ _rendered.rst /spec/ changelogs/rendered.* .hugo_build.lock +hugo_stats.json diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 3760b077..00000000 --- a/.gitmodules +++ /dev/null @@ -1,7 +0,0 @@ -[submodule "themes/docsy"] - path = themes/docsy - # We use our own forked version of the Docsy theme, - # to avoid loading fonts from CDNs, which Docsy currently - # doesn't support (see https://github.com/google/docsy/issues/605). - url = https://github.com/matrix-org/docsy.git - branch = master diff --git a/.htmltest.yaml b/.htmltest.yml similarity index 84% rename from .htmltest.yaml rename to .htmltest.yml index 1563408b..52eedee5 100644 --- a/.htmltest.yaml +++ b/.htmltest.yml @@ -4,3 +4,4 @@ IgnoreDirectoryMissingTrailingSlash: true DirectoryPath: spec CheckExternal: false +IgnoreInternalEmptyHash: true diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 46c6c560..eb3c30f6 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -12,7 +12,7 @@ The documentation style is described at https://github.com/matrix-org/matrix-spec/blob/main/meta/documentation_style.rst. Matrix-spec workflows --------------------- +--------------------- Specification changes ~~~~~~~~~~~~~~~~~~~~~ @@ -72,7 +72,7 @@ ask. 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. The changelog is managed by `Towncrier `_ in the @@ -99,6 +99,8 @@ the ``newsfragments`` directory. The ``type`` can be one of the following: * ``deprecation`` - Used when deprecating something. +* ``removal`` - Used when removing something that was unused or previously deprecated. + All news fragments must have a brief summary explaining the change in the contents of the file. The summary must end in a full stop to be in line with the style guide and formatting must be done using Markdown. @@ -117,7 +119,7 @@ license - in our case, this is Apache Software License v2 (see LICENSE). In order to have a concrete record that your contribution is intentional and you agree to license it under the same terms as the project's license, we've adopted the same lightweight approach used by the `Linux Kernel `_, -`Docker `_, and many other projects: the `Developer Certificate of Origin `_ (DCO). This is a simple declaration that you wrote the contribution or otherwise have the right to contribute it to Matrix:: @@ -163,19 +165,6 @@ include the line in your commit or pull request comment:: Signed-off-by: Your Name -...using your real name; unfortunately pseudonyms and anonymous contributions -can't be accepted. Git makes this trivial - just use the -s flag when you do -``git commit``, having first set ``user.name`` and ``user.email`` git configs -(which you should have done anyway :) - -Private sign off -~~~~~~~~~~~~~~~~ - -If you would like to provide your legal name privately to the Matrix.org -Foundation (instead of in a public commit or comment), you can do so by emailing -your legal name and a link to the pull request to dco@matrix.org. It helps to -include "sign off" or similar in the subject line. You will then be instructed -further. - -Once private sign off is complete, doing so for future contributions will not -be required. +Git allows you to add this signoff automatically when using the ``-s`` +flag to ``git commit``, which uses the name and email set in your +``user.name`` and ``user.email`` git configs. \ No newline at end of file diff --git a/README.md b/README.md index 1482fcdd..91afa6c5 100644 --- a/README.md +++ b/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 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 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. * `/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. +* `/packages`: Various packages for shipping spec files like OpenAPI bindings and data definitions. ## 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: . Note that at least Hugo - v0.93.0 is required. + v0.123.1 is required. Alternatively, use the Docker image at https://hub.docker.com/r/klakegg/hugo/. (The "extended edition" is required to process the SCSS.) -2. Run `npm i` to install the dependencies and fetch the docsy git submodule. - Note that this will require NodeJS to be installed. +2. Run `npm i` to install the dependencies. 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" page and is not required. 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"` 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` -and finally `python ./scripts/dump-swagger.py` to generate it to `./scripts/swagger/api-docs.json`. To make use of the generated file, +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-openapi.py` to generate it to `./scripts/openapi/api-docs.json`. To make use of the generated file, 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 run a local HTTP server by running `./scripts/swagger-http-server.py`, and then view the documentation by - opening `./scripts/swagger-preview.html` in your browser. +* 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/openapi-http-server.py`, and then view the documentation by + opening `./scripts/openapi-preview.html` in your browser. ## Issue tracking diff --git a/assets/css/fonts/Inter.css b/assets/css/fonts/Inter.css new file mode 100644 index 00000000..23ffedf8 --- /dev/null +++ b/assets/css/fonts/Inter.css @@ -0,0 +1,63 @@ +/* cyrillic-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: local('Inter'), url(../../fonts/Inter-cyrillic-ext-normal.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: local('Inter'), url(../../fonts/Inter-cyrillic-normal.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: local('Inter'), url(../../fonts/Inter-greek-ext-normal.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: local('Inter'), url(../../fonts/Inter-greek-normal.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: local('Inter'), url(../../fonts/Inter-vietnamese-normal.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: local('Inter'), url(../../fonts/Inter-latin-ext-normal.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: local('Inter'), url(../../fonts/Inter-latin-normal.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/static/css/fonts/README.md b/assets/css/fonts/README.md similarity index 79% rename from static/css/fonts/README.md rename to assets/css/fonts/README.md index aca33304..0812404a 100644 --- a/static/css/fonts/README.md +++ b/assets/css/fonts/README.md @@ -3,7 +3,7 @@ ## Inter.css `Inter.css` is a local copy of -https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i, modified to pull +https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,100..900&display=swap, modified to pull font files (`.woff2`) from local sources. It was created using `download_google_fonts_css.py`. @@ -15,9 +15,9 @@ load them. Example call: ```sh python3 download_google_fonts_css.py \ - "https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i" \ - ../../fonts \ - ../../fonts + "https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,100..900&display=swap" \ + ../../../static/fonts \ + ../../fonts ``` Which would pop out a `Inter.css` file that should be `@import url("Inter.css")`d diff --git a/static/css/fonts/download_google_fonts_css.py b/assets/css/fonts/download_google_fonts_css.py similarity index 92% rename from static/css/fonts/download_google_fonts_css.py rename to assets/css/fonts/download_google_fonts_css.py index cfb5c052..ba4ddcba 100755 --- a/static/css/fonts/download_google_fonts_css.py +++ b/assets/css/fonts/download_google_fonts_css.py @@ -84,7 +84,6 @@ new_css_file_lines = [] font_lang = None font_family = None font_style = None -font_weight = 0 for line in original_contents: # Check if this line contains a font URL match = re.match(r".*url\((.*)\) format.*", line) @@ -96,16 +95,17 @@ for line in original_contents: resp = requests.get(font_url) if resp.status_code == 200: # Save the font file - filename = "%s-%s-%s-%d.woff2" % ( - font_family, font_lang, font_style, font_weight + filename = "%s-%s-%s.woff2" % ( + font_family, font_lang, font_style ) font_filepath = font_output_dir + filename with open(font_filepath, "wb") as f: print("Writing font file:", font_filepath) f.write(resp.content) - # Replace google URL with local URL - line = re.sub(r"url\(.+\)", f"url({css_font_path + filename})", line) + # Replace google URL with local URL and allow the browser to load the + # local font if it exists. + line = re.sub(r"url\(.+?\)", f"local('{font_family}'), url({css_font_path + filename})", line) else: print("Warning: failed to download font file:", font_url) @@ -121,9 +121,6 @@ for line in original_contents: font_style_match = re.match(r".*font-style: (.+);$", line) if font_style_match: font_style = font_style_match.group(1) - font_weight_match = re.match(r".*font-weight: (.+);$", line) - if font_weight_match: - font_weight = int(font_weight_match.group(1)) # Append the potentially modified line to the new css file new_css_file_lines.append(line) diff --git a/static/css/fonts/requirements.txt b/assets/css/fonts/requirements.txt similarity index 100% rename from static/css/fonts/requirements.txt rename to assets/css/fonts/requirements.txt diff --git a/static/diagrams/README.md b/assets/diagrams/README.md similarity index 52% rename from static/diagrams/README.md rename to assets/diagrams/README.md index 0b74734c..85e4d295 100644 --- a/static/diagrams/README.md +++ b/assets/diagrams/README.md @@ -7,11 +7,17 @@ https://www.diagrams.net/ is a great ([open source](https://github.com/jgraph/dr tool for these sorts of things - include your `.drawio` file next to your diagram. Suggested settings for diagrams.net: -* Export as PNG. -* 100% size. +* Export as WebP. +* 200% size. * `20` for a border width. -* No transparent background, shadow, or grid. -* Include a copy of the diagram. +* Light appearance. +* No shadow, or grid. -To reference a diagram, use the absolute path when compiled. For example, -`![membership-flow-diagram](/diagrams/membership.png)` +To reference a diagram, use the `diagram` shortcode. For example: + +``` +{{% diagram name="membership" alt="Diagram presenting the possible membership state transitions" %}} +``` + +Where `name` is the file name without extension, and `alt` is a textual +replacement for the image, useful for accessibility. diff --git a/static/diagrams/membership.drawio b/assets/diagrams/membership.drawio similarity index 100% rename from static/diagrams/membership.drawio rename to assets/diagrams/membership.drawio diff --git a/assets/diagrams/membership.webp b/assets/diagrams/membership.webp new file mode 100644 index 00000000..08404d1a Binary files /dev/null and b/assets/diagrams/membership.webp differ diff --git a/static/diagrams/threaded-dag-threads.drawio b/assets/diagrams/threaded-dag-threads.drawio similarity index 100% rename from static/diagrams/threaded-dag-threads.drawio rename to assets/diagrams/threaded-dag-threads.drawio diff --git a/assets/diagrams/threaded-dag-threads.webp b/assets/diagrams/threaded-dag-threads.webp new file mode 100644 index 00000000..304ba9b7 Binary files /dev/null and b/assets/diagrams/threaded-dag-threads.webp differ diff --git a/static/diagrams/threaded-dag.drawio b/assets/diagrams/threaded-dag.drawio similarity index 100% rename from static/diagrams/threaded-dag.drawio rename to assets/diagrams/threaded-dag.drawio diff --git a/assets/diagrams/threaded-dag.webp b/assets/diagrams/threaded-dag.webp new file mode 100644 index 00000000..c62873a5 Binary files /dev/null and b/assets/diagrams/threaded-dag.webp differ diff --git a/assets/icons/favicon.ico b/assets/icons/favicon.ico new file mode 100644 index 00000000..58b9ff60 Binary files /dev/null and b/assets/icons/favicon.ico differ diff --git a/assets/icons/favicon.svg b/assets/icons/favicon.svg new file mode 100644 index 00000000..b922fc88 --- /dev/null +++ b/assets/icons/favicon.svg @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/assets/js/toc.js b/assets/js/toc.js new file mode 100644 index 00000000..89a83ced --- /dev/null +++ b/assets/js/toc.js @@ -0,0 +1,169 @@ +/* +Copyright 2020, 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + Only call the given function once every 250 milliseconds to avoid impacting + the performance of the browser. + Source: https://remysharp.com/2010/07/21/throttling-function-calls +*/ +function throttle(fn) { + const threshold = 250; + let last = null; + let deferTimer = null; + + return function (...args) { + const now = new Date(); + + if (last && now < last + threshold) { + // Hold on to it. + clearTimeout(deferTimer); + deferTimer = setTimeout(() => { + last = now; + fn.apply(this, args); + }, threshold); + } else { + last = now; + fn.apply(this, args); + } + } +} + +/* + Get the list of headings that appear in the ToC. + This is not as simple as querying all the headings in the content, because + some headings are not rendered in the ToC (e.g. in the endpoint definitions). +*/ +function getHeadings() { + let headings = []; + + // First get the anchors in the ToC. + const toc_anchors = document.querySelectorAll("#toc nav a"); + + for (const anchor of toc_anchors) { + // Then get the heading from its selector in the anchor's href. + const selector = anchor.getAttribute("href"); + if (!selector) { + console.error("Got ToC anchor without href"); + continue; + } + + const heading = document.querySelector(selector); + if (!heading) { + console.error("Heading not found for selector:", selector); + continue; + } + + headings.push(heading); + } + + return headings; +} + +/* + Get the heading of the text visible at the top of the viewport. + This is the first heading above or at the top of the viewport. +*/ +function getCurrentHeading(headings, headerOffset) { + const scrollTop = document.documentElement.scrollTop; + let prevHeading = null; + let currentHeading = null; + let index = 0; + + for (const heading of headings) { + // Compute the position compared to the viewport. + const rect = heading.getBoundingClientRect(); + + if (rect.top >= headerOffset && rect.top <= headerOffset + 30) { + // This heading is at the top of the viewport, this is the current heading. + currentHeading = heading; + break; + } + if (rect.top >= headerOffset) { + // This is in or below the viewport, the current heading should be the + // previous one. + if (prevHeading) { + currentHeading = prevHeading; + } else { + // The first heading does not have a prevHeading. + currentHeading = heading; + } + break; + } + + prevHeading = heading; + index += 1; + } + + // At the bottom of the page we might not have a heading. + if (!currentHeading) { + currentHeading = prevHeading; + } + + return currentHeading; +} + +/* + Select the ToC entry that points to the given ID. + Clear any previously highlighted ToC items, select the new one, + and adjust the ToC scroll position. +*/ +function selectTocEntry(id) { + // Deselect previously selected entries. + const activeEntries = document.querySelectorAll("#toc nav a.active"); + for (const activeEntry of activeEntries) { + activeEntry.classList.remove('active'); + } + + // Find the new entry and select it. + const newEntry = document.querySelector(`#toc nav a[href="#${id}"]`); + if (!newEntry) { + console.error("ToC entry not found for ID:", id); + return; + } + newEntry.classList.add('active'); + + // Don't scroll the sidebar nav if the main content is not scrolled + const nav = document.querySelector("#td-section-nav"); + const content = document.querySelector("html"); + if (content.scrollTop !== 0) { + nav.scrollTop = newEntry.offsetTop - 100; + } else { + nav.scrollTop = 0; + } +} + +/* + Track when the view is scrolled, and use this to update the highlight for the + corresponding ToC entry. +*/ +window.addEventListener('DOMContentLoaded', () => { + // Part of the viewport is below the header so we should take it into account. + const headerOffset = document.querySelector("body > header > nav").clientHeight; + const headings = getHeadings(); + + const onScroll = throttle((_e) => { + // Update the ToC. + let heading = getCurrentHeading(headings, headerOffset); + selectTocEntry(heading.id); + }); + + // Initialize the state of the ToC. + onScroll(); + + // Listen to scroll and resizing changes. + document.addEventListener('scroll', onScroll, false); + document.addEventListener('resize', onScroll, false); +}); diff --git a/assets/scss/custom.scss b/assets/scss/_styles_project.scss similarity index 84% rename from assets/scss/custom.scss rename to assets/scss/_styles_project.scss index c147b645..9b020715 100644 --- a/assets/scss/custom.scss +++ b/assets/scss/_styles_project.scss @@ -18,9 +18,6 @@ limitations under the License. Custom SCSS for the Matrix spec */ -@import "variables_project"; -@import "variables"; - /* Import the CSS classes for the syntax highlighter. * * This is generated with: @@ -29,12 +26,6 @@ Custom SCSS for the Matrix spec */ @import "syntax.scss"; -/* Workaround for https://github.com/google/docsy/issues/1116: - * fix scroll-anchoring */ -.td-outer { - height: auto; -} - /* Overrides for the navbar */ .td-navbar { box-shadow: 0px 0px 8px rgba(179, 179, 179, 0.25); @@ -43,10 +34,17 @@ Custom SCSS for the Matrix spec .navbar-brand { font-size: 1.1rem; + /* Allow the text to wrap if it is wider than the viewport */ + text-align: center; + white-space: normal; + .navbar-version { color: $secondary; } + } + .nav-link { + font-weight: normal; } a { @@ -114,7 +112,7 @@ Custom SCSS for the Matrix spec } } -@media (min-width: 768px) { +@include media-breakpoint-up(md) { @supports (position: sticky) { .td-sidebar-nav { /* This overrides calc(100vh - 10rem);, which gives us a blank space at the bottom of the sidebar */ @@ -124,8 +122,11 @@ Custom SCSS for the Matrix spec } /* Customise footer */ -footer { +.td-footer { box-shadow: 0px 0px 8px rgba(179, 179, 179, 0.25); + padding-top: 2rem; + color: var(--bs-body-color); + background-color: var(--bs-body-color-bg); } /* Auto numbering for headings */ @@ -171,6 +172,13 @@ footer { } +/* Remove some padding before the main content, when the sidebar is disabled */ +.td-main main { + @include media-breakpoint-down(md) { + padding-top: 0; + } +} + /* Adjust the scroll margin for everything in the main content, so that * it doesn't disappear behind the header bar */ .td-content * { @@ -266,33 +274,10 @@ footer { border-left-width: 5px; background: $warning-background; } - - // XXX: See the added-in-paragraph.html shortcode for more information on these styles. - &.added-in-paragraph { - // Remove the padding and margin to remove the box look - margin: 0 !important; // !important on both to override table-related rules - padding: 0 !important; - - // Make pairs of "added-in" and content inline to each other. We do pairs so authors can - // describe two paragraphs with added-in prefixes within a single box, reducing DOM - // complexity. Each paragraph is expected to be prefixed with an added-in, however. - // - // XXX: We assume the added-in and text will be rendered as paragraph elements. - > p { - display: inline; - } - > p:nth-child(2n) { // "even" rule to target just the content paragraphs - // Force a paragraph break after the content (insert a couple
tags) - &::after { - content: '\A\A'; - white-space: pre; - } - } - } } /* 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; padding: 0.85rem; margin: 0.85rem 0; @@ -346,7 +331,7 @@ footer { } p code, table code { - background-color: inherit; + background-color: transparent; } table { @@ -396,6 +381,12 @@ footer { th, td, caption { padding: 1rem; + border-top: 1px $table-border-color solid; + } + + td > p:last-child { + // Avoid unnecessary space at the bottom of the cells. + margin-bottom: 0; } &.object-table, &.response-table, &.content-type-table { @@ -408,14 +399,12 @@ footer { // ... but avoid double border between caption and table border-bottom: 0; + + background-color: $secondary-lighter-background; } - caption, tbody tr { - background-color: $table-row-default; - } - - tbody tr:nth-child(even) { - background-color: $table-row-alternate; + tbody tr { + --bs-table-striped-bg: #{$secondary-lighter-background}; } } @@ -427,6 +416,31 @@ footer { &.basic-info th { width: 15rem; } + + /* Arrange rows vertically when horizontal space is constrained to avoid overflowing */ + @include media-breakpoint-down(sm) { + /* Make cells full width without vertical margin */ + &.basic-info th, &.basic-info td { + width: 100%; + display: inline-block; + margin-top: 0; + margin-bottom: 0; + } + + /* Remove border and padding between header & data cells to make them appear like a single cell */ + &.basic-info td { + padding-top: 0; + border-top: none; + } + &.basic-info th { + border-bottom: none; + } + + /* Remove top border on all but the first header cell to prevent double borders between rows */ + &.basic-info tr + tr th { + border-top: none; + } + } } pre { @@ -471,12 +485,18 @@ of .td-content. This applies the same style to any blockquotes that descend from Make padding symmetrical (this selector is used in the default styles to apply padding-left: 3rem) */ .pl-md-5, .px-md-5 { - padding-right: 3rem; + @include media-breakpoint-up(md) { + padding-right: 3rem; + } } /* Adjust default styles for info banner */ .pageinfo-primary { - max-width: 80%; + @include media-breakpoint-up(lg) { + max-width: 80%; + } + margin-top: 0; + margin-right: 0; margin-left: 0; border: 0; border-left: solid 5px $secondary; @@ -517,3 +537,15 @@ dd { 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; + } +} \ No newline at end of file diff --git a/assets/scss/_variables_project.scss b/assets/scss/_variables_project.scss index 8ff5fe98..c2ec03c6 100644 --- a/assets/scss/_variables_project.scss +++ b/assets/scss/_variables_project.scss @@ -20,7 +20,7 @@ $dark: #333; $gray-100: #FBFBFB; $secondary-background: #E5F5FB; -$secondary-lighter-background: #F4FaFC; +$secondary-lighter-background: #F4FAFC; $secondary-lightest-background: #FBFDFD; @@ -33,20 +33,24 @@ $warning-background: #FFE0E0; // colours for definition tables. // the border colour matches that used for "highlight" divs $table-border-color: rgba(black, .125); -$table-row-alternate: $secondary-lightest-background; -$table-row-default: $secondary-lighter-background; +$table-bg: $secondary-lightest-background; /* Configure docsy to use the default system fonts instead of Google Fonts. * See https://www.docsy.dev/docs/adding-content/lookandfeel/#fonts */ $td-enable-google-fonts: false; /* - * Replace the default font with Inter. - * - * The $font-family-sans-serif definition here overrides the default value set by docsy: - * https://github.com/matrix-org/docsy/blob/66a4e61d2d34edc7196b9df83a7d09cd4af14b47/assets/scss/_variables.scss#L68 - * and adds "Inter" to the front. - * - * The font itself is loaded via stylesheet link layouts/partials/hooks/head-end.html. + * The $font-family-sans-serif definition here overrides the default value set by docsy + * (https://github.com/matrix-org/docsy/blob/66a4e61d2d34edc7196b9df83a7d09cd4af14b47/assets/scss/_variables.scss#L68) */ -$font-family-sans-serif: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; +$font-family-sans-serif: + // Add "Inter" to the front, making it the default. The font itself is loaded via stylesheet + // links in layouts/partials/hooks/head-end.html. + "Inter", + -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", + // Insert fonts suited for mathematical symbols on different platforms before "Arial" + "STIX Two Math", "Cambria Math", "Noto Sans Math", "Dejavu Sans", + Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + +// Disable smooth scrolling as it makes TOC highlighting jump during the transition. +$enable-smooth-scroll: false; diff --git a/changelogs/appendices/newsfragments/1573.clarification b/changelogs/appendices/newsfragments/1573.clarification deleted file mode 100644 index 7210ae76..00000000 --- a/changelogs/appendices/newsfragments/1573.clarification +++ /dev/null @@ -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 diff --git a/changelogs/appendices/newsfragments/1583.feature b/changelogs/appendices/newsfragments/1583.feature deleted file mode 100644 index b24077c6..00000000 --- a/changelogs/appendices/newsfragments/1583.feature +++ /dev/null @@ -1 +0,0 @@ -Allow `+` in Matrix IDs, per [MSC4009](https://github.com/matrix-org/matrix-spec-proposals/pull/4009). diff --git a/changelogs/application_service/newsfragments/1584.clarification b/changelogs/application_service/newsfragments/1584.clarification deleted file mode 100644 index 098c1260..00000000 --- a/changelogs/application_service/newsfragments/1584.clarification +++ /dev/null @@ -1 +0,0 @@ -Fix JSON schema of custom fields in query. diff --git a/changelogs/client_server/newsfragments/1552.clarification b/changelogs/client_server/newsfragments/1552.clarification deleted file mode 100644 index 3f8cdbfb..00000000 --- a/changelogs/client_server/newsfragments/1552.clarification +++ /dev/null @@ -1 +0,0 @@ -Fix missing `type` property in the JSON schema definition of the `m.reaction` event. Contributed by @chebureki. diff --git a/changelogs/client_server/newsfragments/1563.clarification b/changelogs/client_server/newsfragments/1563.clarification deleted file mode 100644 index 1d6ef324..00000000 --- a/changelogs/client_server/newsfragments/1563.clarification +++ /dev/null @@ -1 +0,0 @@ -Make sure examples types match schema in definitions. diff --git a/changelogs/client_server/newsfragments/1564.clarification b/changelogs/client_server/newsfragments/1564.clarification deleted file mode 100644 index 59fcf699..00000000 --- a/changelogs/client_server/newsfragments/1564.clarification +++ /dev/null @@ -1 +0,0 @@ -Allow `null` in `room_types` in `POST /publicRooms` endpoints schemas. diff --git a/changelogs/client_server/newsfragments/1578.clarification b/changelogs/client_server/newsfragments/1578.clarification deleted file mode 100644 index 09e9dc70..00000000 --- a/changelogs/client_server/newsfragments/1578.clarification +++ /dev/null @@ -1 +0,0 @@ -Fix broken header formatting. Contributed by @midnightveil. diff --git a/changelogs/client_server/newsfragments/1579.clarification b/changelogs/client_server/newsfragments/1579.clarification deleted file mode 100644 index d53f2352..00000000 --- a/changelogs/client_server/newsfragments/1579.clarification +++ /dev/null @@ -1 +0,0 @@ -Render binary request and response bodies. diff --git a/changelogs/client_server/newsfragments/1585.clarification b/changelogs/client_server/newsfragments/1585.clarification deleted file mode 100644 index 5b26ae97..00000000 --- a/changelogs/client_server/newsfragments/1585.clarification +++ /dev/null @@ -1 +0,0 @@ -Remove unnecessary `oneOf`s in JSON schemas. diff --git a/changelogs/client_server/newsfragments/1590.clarification b/changelogs/client_server/newsfragments/1590.clarification deleted file mode 100644 index 1642357d..00000000 --- a/changelogs/client_server/newsfragments/1590.clarification +++ /dev/null @@ -1 +0,0 @@ -Fix description of MAC calculation in SAS verification. \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1593.clarification b/changelogs/client_server/newsfragments/1593.clarification deleted file mode 100644 index 2f6cbee6..00000000 --- a/changelogs/client_server/newsfragments/1593.clarification +++ /dev/null @@ -1 +0,0 @@ -Update link to SAS emoji definition data. diff --git a/changelogs/client_server/newsfragments/1597.clarification b/changelogs/client_server/newsfragments/1597.clarification deleted file mode 100644 index 3ccb2333..00000000 --- a/changelogs/client_server/newsfragments/1597.clarification +++ /dev/null @@ -1 +0,0 @@ -Fix various typos throughout the specification. diff --git a/changelogs/client_server/newsfragments/2038.clarification b/changelogs/client_server/newsfragments/2038.clarification new file mode 100644 index 00000000..169ca65c --- /dev/null +++ b/changelogs/client_server/newsfragments/2038.clarification @@ -0,0 +1 @@ +Clarify wording in the `/join` endpoints' summaries and descriptions. Contributed by @HarHarLinks. diff --git a/changelogs/header.md b/changelogs/header.md deleted file mode 100644 index 21b35106..00000000 --- a/changelogs/header.md +++ /dev/null @@ -1,16 +0,0 @@ - - -## VERSION - - - - -
Git commithttps://github.com/matrix-org/matrix-spec/tree/VERSION
Release dateDATE
- - diff --git a/changelogs/identity_service/newsfragments/1563.clarification b/changelogs/identity_service/newsfragments/1563.clarification deleted file mode 100644 index 1d6ef324..00000000 --- a/changelogs/identity_service/newsfragments/1563.clarification +++ /dev/null @@ -1 +0,0 @@ -Make sure examples types match schema in definitions. diff --git a/changelogs/internal/newsfragments/1310.feature b/changelogs/internal/newsfragments/1310.feature deleted file mode 100644 index 9aaa18b6..00000000 --- a/changelogs/internal/newsfragments/1310.feature +++ /dev/null @@ -1 +0,0 @@ -Upgrade Swagger data to OpenAPI 3.1. diff --git a/changelogs/internal/newsfragments/1542.clarification b/changelogs/internal/newsfragments/1542.clarification deleted file mode 100644 index 422a4eef..00000000 --- a/changelogs/internal/newsfragments/1542.clarification +++ /dev/null @@ -1 +0,0 @@ -Update the CI to validate the file extension of changelog entries. \ No newline at end of file diff --git a/changelogs/internal/newsfragments/1549.clarification b/changelogs/internal/newsfragments/1549.clarification deleted file mode 100644 index 67dbd67e..00000000 --- a/changelogs/internal/newsfragments/1549.clarification +++ /dev/null @@ -1 +0,0 @@ -Disclosure sections now only display their title when collapsed. diff --git a/changelogs/internal/newsfragments/1551.clarification b/changelogs/internal/newsfragments/1551.clarification deleted file mode 100644 index b9f32571..00000000 --- a/changelogs/internal/newsfragments/1551.clarification +++ /dev/null @@ -1 +0,0 @@ -Fix the sidebar in recent versions of Hugo diff --git a/changelogs/internal/newsfragments/1556.clarification b/changelogs/internal/newsfragments/1556.clarification deleted file mode 100644 index 05c5897e..00000000 --- a/changelogs/internal/newsfragments/1556.clarification +++ /dev/null @@ -1 +0,0 @@ -Bump jsonschema to validate JSON Schemas against Draft 2020-12. diff --git a/changelogs/internal/newsfragments/1558.clarification b/changelogs/internal/newsfragments/1558.clarification deleted file mode 100644 index 29e1c1d0..00000000 --- a/changelogs/internal/newsfragments/1558.clarification +++ /dev/null @@ -1 +0,0 @@ -Use Redocly CLI to validate OpenAPI definitions. diff --git a/changelogs/internal/newsfragments/1561.clarification b/changelogs/internal/newsfragments/1561.clarification deleted file mode 100644 index 6381ddf3..00000000 --- a/changelogs/internal/newsfragments/1561.clarification +++ /dev/null @@ -1 +0,0 @@ -Use tag name as the OpenAPI definition version. diff --git a/changelogs/internal/newsfragments/1562.clarification b/changelogs/internal/newsfragments/1562.clarification deleted file mode 100644 index 6882cad1..00000000 --- a/changelogs/internal/newsfragments/1562.clarification +++ /dev/null @@ -1 +0,0 @@ -Make sure version in x-changedInMatrixVersion is a string. diff --git a/changelogs/internal/newsfragments/1582.clarification b/changelogs/internal/newsfragments/1582.clarification deleted file mode 100644 index 2f048a06..00000000 --- a/changelogs/internal/newsfragments/1582.clarification +++ /dev/null @@ -1 +0,0 @@ -Clarify usage of ABNF for grammar in the documentation style guide. diff --git a/changelogs/internal/newsfragments/1591.clarification b/changelogs/internal/newsfragments/1591.clarification deleted file mode 100644 index 3ee889ff..00000000 --- a/changelogs/internal/newsfragments/1591.clarification +++ /dev/null @@ -1 +0,0 @@ -Update the version of Hugo used to render the spec to v0.113.0. diff --git a/changelogs/internal/newsfragments/1598.clarification b/changelogs/internal/newsfragments/1598.clarification deleted file mode 100644 index 1077e83c..00000000 --- a/changelogs/internal/newsfragments/1598.clarification +++ /dev/null @@ -1 +0,0 @@ -Fix rendered changelog with new version of towncrier. diff --git a/changelogs/internal/newsfragments/1601.clarification b/changelogs/internal/newsfragments/1601.clarification deleted file mode 100644 index 7d3b9b12..00000000 --- a/changelogs/internal/newsfragments/1601.clarification +++ /dev/null @@ -1 +0,0 @@ -Improve the layout of tables on desktop displays. Contributed by Martin Fischer. diff --git a/changelogs/internal/newsfragments/2033.clarification b/changelogs/internal/newsfragments/2033.clarification new file mode 100644 index 00000000..9d3e7596 --- /dev/null +++ b/changelogs/internal/newsfragments/2033.clarification @@ -0,0 +1 @@ +Generate the changelog release info with Hugo, rather than the changelog generation script. diff --git a/changelogs/internal/newsfragments/2041.clarification b/changelogs/internal/newsfragments/2041.clarification new file mode 100644 index 00000000..fd9a66f7 --- /dev/null +++ b/changelogs/internal/newsfragments/2041.clarification @@ -0,0 +1 @@ +Update release steps documentation. \ No newline at end of file diff --git a/changelogs/server_server/newsfragments/1521.clarification b/changelogs/server_server/newsfragments/1521.clarification deleted file mode 100644 index 6c1ebf9d..00000000 --- a/changelogs/server_server/newsfragments/1521.clarification +++ /dev/null @@ -1 +0,0 @@ -Document why `/state_ids` can respond with a 404. diff --git a/changelogs/server_server/newsfragments/1559.clarification b/changelogs/server_server/newsfragments/1559.clarification deleted file mode 100644 index 401a94e0..00000000 --- a/changelogs/server_server/newsfragments/1559.clarification +++ /dev/null @@ -1 +0,0 @@ -Fix definition of response of `POST /_matrix/federation/v1/user/keys/claim`. diff --git a/changelogs/server_server/newsfragments/1560.clarification b/changelogs/server_server/newsfragments/1560.clarification deleted file mode 100644 index e717dda4..00000000 --- a/changelogs/server_server/newsfragments/1560.clarification +++ /dev/null @@ -1 +0,0 @@ -Fix level of examples in server keys definition. diff --git a/changelogs/server_server/newsfragments/1563.clarification b/changelogs/server_server/newsfragments/1563.clarification deleted file mode 100644 index 1d6ef324..00000000 --- a/changelogs/server_server/newsfragments/1563.clarification +++ /dev/null @@ -1 +0,0 @@ -Make sure examples types match schema in definitions. diff --git a/changelogs/server_server/newsfragments/1564.clarification b/changelogs/server_server/newsfragments/1564.clarification deleted file mode 100644 index 59fcf699..00000000 --- a/changelogs/server_server/newsfragments/1564.clarification +++ /dev/null @@ -1 +0,0 @@ -Allow `null` in `room_types` in `POST /publicRooms` endpoints schemas. diff --git a/changelogs/server_server/newsfragments/1578.clarification b/changelogs/server_server/newsfragments/1578.clarification deleted file mode 100644 index 09e9dc70..00000000 --- a/changelogs/server_server/newsfragments/1578.clarification +++ /dev/null @@ -1 +0,0 @@ -Fix broken header formatting. Contributed by @midnightveil. diff --git a/changelogs/template.md.jinja b/changelogs/template.md.jinja index 38de4b92..cc456efd 100644 --- a/changelogs/template.md.jinja +++ b/changelogs/template.md.jinja @@ -1,7 +1,7 @@ {% for section_name, section in sections.items() %} {% if section_name %} -### {{section_name}} +## {{section_name}} {% endif %} {% if section %} diff --git a/config.toml b/config/_default/hugo.toml similarity index 74% rename from config.toml rename to config/_default/hugo.toml index c6f1bd45..6a95c9bb 100644 --- a/config.toml +++ b/config/_default/hugo.toml @@ -1,29 +1,44 @@ +# Default settings. + baseURL = "/" title = "Matrix Specification" -# Prepends absolute URLs with the baseURL. Useful when hosting on non-root -# paths, such as /unstable. -canonifyURLs = 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 # links to it when used with a --baseURL (for example, https://spec.matrix.org/v1.4/ # contains ``). -disableKinds = ["taxonomy", "taxonomyTerm", "RSS"] +disableKinds = ["taxonomy", "RSS"] [languages] [languages.en] title = "Matrix Specification" -description = "Home of the Matrix specification for decentralised communication" languageName ="English" # Weight used for sorting. weight = 1 +[languages.en.params] +description = "Home of the Matrix specification for decentralised communication" + +# 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.tableOfContents] + startLevel = 2 + endLevel = 6 + ordered = true [markup.goldmark] [markup.goldmark.renderer] # Enables us to render raw HTML @@ -42,7 +57,6 @@ weight = 1 [params] copyright = "The Matrix.org Foundation CIC" -privacy_policy = "https://matrix.org/legal/privacy-notice" [params.version] # must be one of "unstable", "current", "historical" @@ -53,13 +67,11 @@ 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 # of the spec. CI will set these values here automatically when a release git tag (i.e `v1.5`) is created. # major = "1" -# minor = "7" -# release_date = "May 25, 2023" +# minor = "13" +# release_date = "December 19, 2024" # User interface configuration [params.ui] -# Set to true to disable the About link in the site footer -footer_about_disable = false # Collapse HTTP API and event
elements rendered_data_collapsed = false # Hide the search entry in the sidebar @@ -75,22 +87,28 @@ sidebar_menu_compact = true # icon = "fa fa-envelope" # desc = "Discussion and help from your fellow users" # Developer relevant links. These will show up on right side of footer and in the community page if you have one. -[[params.links.developer]] +# [[params.links.developer]] +# name = "GitHub" +# url = "https://github.com/matrix-org" +# icon = "fab fa-github" +# desc = "Matrix on GitHub" +# Custom links shown in the center of the footer. (Only supported by our fork of docsy's 'footer/central' partial.) +[[params.links.bottom]] name = "GitHub" url = "https://github.com/matrix-org" icon = "fab fa-github" desc = "Matrix on GitHub" -[[params.links.developer]] +[[params.links.bottom]] name = "GitLab" url = "https://gitlab.matrix.org/matrix-org" icon = "fab fa-gitlab" desc = "Matrix on GitLab" -[[params.links.developer]] +[[params.links.bottom]] name = "YouTube" url = "https://www.youtube.com/channel/UCVFkW-chclhuyYRbmmfwt6w" icon = "fab fa-youtube" desc = "Matrix YouTube channel" -[[params.links.developer]] +[[params.links.bottom]] name = "Twitter" url = "https://twitter.com/matrixdotorg" icon = "fab fa-twitter" @@ -111,3 +129,21 @@ sidebar_menu_compact = true X-Frame-Options = "sameorigin" Access-Control-Allow-Origin = "*" Access-Control-Allow-Methods = "GET" + +# hugo module configuration + +[module] + [module.hugoVersion] + extended = true + min = "0.123.1" + [[module.imports]] + path = "github.com/matrix-org/docsy" + disable = false + +# custom output formats + +[outputFormats] + [outputFormats.Checklist] + mediaType = "text/markdown" + isPlainText = true + baseName = "checklist" diff --git a/config/production/hugo.toml b/config/production/hugo.toml new file mode 100644 index 00000000..61079826 --- /dev/null +++ b/config/production/hugo.toml @@ -0,0 +1,6 @@ +# Settings only required when the website is built for production. + +# Enable stats to use them to optimize the CSS. +[build] + [build.buildStats] + enable = true diff --git a/content/_index.md b/content/_index.md index 69832f2e..e56eb4d0 100644 --- a/content/_index.md +++ b/content/_index.md @@ -56,9 +56,6 @@ The principles that Matrix attempts to follow are: the global Matrix network - Fully open standard - publicly documented standard with no IP or patent licensing encumbrances - - Fully open source reference implementation - liberally-licensed - example implementations with no IP or patent licensing - encumbrances - Empowering the end-user - The user should be able to choose the server and clients they use @@ -99,6 +96,20 @@ services - be that for instant messages, VoIP call setups, or any other objects that need to be reliably and persistently pushed from A to B in an interoperable and federated manner. +### Requirement levels + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", +"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" across all parts of the +specification are to be interpreted as described in +[RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119). + +Some entire sections of the specification might be optional depending on the +circumstances. For example, the +[modules of the client-server API](/client-server-api/#modules) +apply depending on the use case. The requirement level expressed by the above +key words appearing in such a section is only relevant if the section itself is +applicable. + ### Spec Change Proposals To propose a change to the Matrix Spec, see the explanations at @@ -419,9 +430,16 @@ into the `m.` namespace. ### Timestamps -Unless otherwise stated, timestamps are measured as milliseconds since -the Unix epoch. Throughout the specification this may be referred to as -POSIX, Unix, or just "time in milliseconds". +Unless otherwise stated, timestamps are the number of milliseconds +elapsed since the unix epoch (1970-01-01 00:00:00 UTC), but not counting +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 diff --git a/content/appendices.md b/content/appendices.md index 52b149ae..32b138f5 100644 --- a/content/appendices.md +++ b/content/appendices.md @@ -136,12 +136,12 @@ removing insignificant whitespace, fractions, exponents and redundant character escapes. value = false / null / true / object / array / number / string - false = %x66.61.6c.73.65 - null = %x6e.75.6c.6c + false = %x66.61.6C.73.65 + null = %x6E.75.6C.6C true = %x74.72.75.65 - object = %x7B [ member *( %x2C member ) ] %7D + object = %x7B [ member *( %x2C member ) ] %x7D member = string %x3A value - array = %x5B [ value *( %x2C value ) ] %5B + array = %x5B [ value *( %x2C value ) ] %x5D number = [ %x2D ] int int = %x30 / ( %x31-39 *digit ) digit = %x30-39 @@ -556,7 +556,7 @@ The `domain` of a user ID is the [server name](#server-name) of the homeserver which allocated the account. The length of a user ID, including the `@` sigil and the domain, MUST -NOT exceed 255 characters. +NOT exceed 255 bytes. The complete grammar for a legal user ID is: @@ -677,6 +677,9 @@ unicode codepoints, including control characters, except `:` and `NUL` (U+0000), but it is recommended to only include ASCII letters and digits (`A-Z`, `a-z`, `0-9`) when generating them. +The length of a room ID, including the `!` sigil and the domain, MUST +NOT exceed 255 bytes. + #### Room Aliases A room may have zero or more aliases. A room alias has the format: @@ -690,8 +693,8 @@ homeserver to look up the alias. The localpart of a room alias may contain any valid unicode codepoints except `:`. -Room aliases MUST NOT exceed 255 bytes as UTF-8 (including the `#` sigil -and the domain). +The length of a room alias, including the `#` sigil and the domain, MUST +NOT exceed 255 bytes. #### Event IDs @@ -703,10 +706,12 @@ However, the precise format depends upon the [room version specification](/rooms): early room versions included a `domain` component, whereas more recent versions omit the domain and use a base64-encoded hash instead. +In addition to the requirements of the room version, the length of an event ID, +including the `$` sigil and the domain where present, MUST NOT exceed 255 bytes. + Event IDs are case-sensitive. They are not meant to be human-readable. They are intended to be treated as fully opaque strings by clients. - ### URIs There are two major kinds of referring to a resource in Matrix: matrix.to @@ -762,7 +767,7 @@ Specifically, the following mappings are used: * `r` for room aliases. * `u` for users. * `roomid` for room IDs (note the distinction from room aliases). -* `e` for events, when after a room reference (`r` or `roomid`). +* `e` for events, when after a room ID (`roomid`). Use of `e` after a room alias (`r`) is deprecated. {{% boxes/note %}} During development of this URI format, types of `user`, `room`, and `event` @@ -772,6 +777,13 @@ wish to consider handling them as `u`, `r`, and `e` respectively. `roomid` was otherwise unchanged. {{% /boxes/note %}} +{{% boxes/note %}} +{{% changed-in v="1.11" %}} +Referencing event IDs within a room identified by room alias (`r`) rather than room ID +(`roomid`) is now deprecated. We are not aware of these ever having been used in +practice, and are nonsensical given room aliases are mutable. +{{% /boxes/note %}} + The `id without sigil` is simply the identifier for the entity without the defined sigil. For example, `!room:example.org` becomes `room:example.org` (`!` is the sigil for room IDs). The sigils are described under the @@ -816,7 +828,6 @@ Examples of common URIs are: * Link to `#somewhere:example.org`: `matrix:r/somewhere:example.org` * Link to `!somewhere:example.org`: `matrix:roomid/somewhere:example.org?via=elsewhere.ca` -* Link to `$event` in `#somewhere:example.org`: `matrix:r/somewhere:example.org/e/event` * Link to `$event` in `!somewhere:example.org`: `matrix:roomid/somewhere:example.org/e/event?via=elsewhere.ca` * Link to chat with `@alice:example.org`: `matrix:u/alice:example.org?action=chat` @@ -826,9 +837,9 @@ A suggested client implementation algorithm is available in the #### matrix.to navigation {{% boxes/note %}} -This namespacing existed prior to a `matrix:` scheme. This is **not** -meant to be interpreted as an available web service - see below for more -details. +matrix.to is a Namespace URI which existed prior to a `matrix:` URI scheme. +This is **not** meant to be interpreted as an available web service - see +below for more details. {{% /boxes/note %}} A matrix.to URI has the following format, based upon the specification @@ -860,10 +871,16 @@ Examples of matrix.to URIs are: * Link to `#somewhere:example.org`: `https://matrix.to/#/%23somewhere%3Aexample.org` * Link to `!somewhere:example.org`: `https://matrix.to/#/!somewhere%3Aexample.org?via=elsewhere.ca` -* Link to `$event` in `#somewhere:example.org`: `https://matrix.to/#/%23somewhere:example.org/%24event%3Aexample.org` * Link to `$event` in `!somewhere:example.org`: `https://matrix.to/#/!somewhere%3Aexample.org/%24event%3Aexample.org?via=elsewhere.ca` * Link to `@alice:example.org`: `https://matrix.to/#/%40alice%3Aexample.org` +{{% boxes/note %}} +{{% changed-in v="1.11" %}} +Referencing event IDs within a room identified by room alias rather than room ID +is now deprecated. We are not aware of these ever having been used in +practice, and are nonsensical given room aliases are mutable. +{{% /boxes/note %}} + {{% boxes/note %}} Historically, clients have not produced URIs which are fully encoded. Clients should try to interpret these cases to the best of their @@ -938,6 +955,50 @@ unique servers based on the following criteria: specify the servers it can. For example, a room with only 2 users in it would result in maximum 2 `via` parameters. +### Opaque Identifiers + +The specification defines some identifiers to use the *Opaque Identifier +Grammar*. This is a common grammar intended for non-user-visible identifiers +which do not require parsing or interpretation (other than as a unique +identifier). + +The grammar is defined as: + +* Identifiers must be entirely composed of the characters `[0-9]`, `[A-Z]`, + `[a-z]`, `-`, `.`, `_`, and `~`. +* Unless otherwise specified, identifiers must be at least one character and at + most 255 characters in length. + +{{% boxes/note %}} +The acceptable character set matches the unreserved character set in [RFC +3986](https://datatracker.ietf.org/doc/html/rfc3986#section-2.3). +{{% /boxes/note %}} + +## Cryptographic key representation + +Sometimes it is necessary to present a private cryptographic key in the user +interface. + +When this happens, the key SHOULD be presented as a string formatted as +follows: + +1. A byte array is created, consisting of two bytes `0x8B` and `0x01`, + followed by the raw key. +2. All the bytes in the array above, including the two header bytes, + are XORed together to form a parity byte. This parity byte is + appended to the byte array. +3. The byte array is encoded using base58, using the the alphabet + `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`. +4. A space is added after every 4th character. + +When reading in a key, clients should disregard whitespace, and +perform the reverse of steps 1 through 4. + +{{% boxes/note %}} +The base58 alphabet is the same as that used for [Bitcoin +addresses](https://en.bitcoin.it/wiki/Base58Check_encoding#Base58_symbol_chart). +{{% /boxes/note %}} + ## 3PID Types Third-party Identifiers (3PIDs) represent identifiers on other diff --git a/content/application-service-api.md b/content/application-service-api.md index f3db06cf..2882f3d9 100644 --- a/content/application-service-api.md +++ b/content/application-service-api.md @@ -207,6 +207,39 @@ processed the events. {{% http-api spec="application-service" api="transactions" %}} +##### Pushing ephemeral data + +{{% added-in v="1.13" %}} + +If the `receive_ephemeral` settings is enabled in the [registration](#registration) +file, homeservers MUST send ephemeral data that is relevant to the application +service via the transaction API, using the `ephemeral` property of the request's +body. This property is an array that is effectively a combination of the +`presence` and `ephemeral` sections of the client-server [`/sync`](/client-server-api/#get_matrixclientv3sync) +API. + +There are currently three event types that can be delivered to an application +service: + +- **[`m.presence`](/client-server-api/#mpresence)**: MUST be sent to the +application service if the data would apply contextually. For example, a +presence update for a user an application service shares a room with, or +matching one of the application service's namespaces. +- **[`m.typing`](/client-server-api/#mtyping)**: MUST be sent to the application +service under the same rules as regular events, meaning that the application +service must have registered interest in the room itself, or in a user that is +in the room. The data MUST use the same format as the client-server API, with +the addition of a `room_id` property at the top level to identify the room that +they were sent in. +- **[`m.receipt`](/client-server-api/#mreceipt)**: MUST be sent to the +application service under the same rules as regular events, meaning that the +application service must have registered interest in the room itself, or in a +user that is in the room. The data MUST use the same format as the client-server +API, with the addition of a `room_id` property at the top level to identify the +room that they were sent in. [Private read receipts](/client-server-api/#private-read-receipts) +MUST only be sent for users matching one of the application service's +namespaces. Normal read receipts and threaded read receipts are always sent. + #### Pinging {{% added-in v="1.7" %}} @@ -436,6 +469,12 @@ an application service-defined namespace will receive the same `M_EXCLUSIVE` error code, but only if the application service has defined the namespace as `exclusive`. +If `/register` or `/login` is called with the `m.login.application_service` +login type, but without a valid `as_token`, the endpoints will return an error +with the `M_MISSING_TOKEN` or `M_UNKNOWN_TOKEN` error code and 401 as the HTTP +status code. This is the same behavior as invalid auth in the client-server API +(see [Using access tokens](/client-server-api/#using-access-tokens)). + #### Pinging {{% added-in v="1.7" %}} diff --git a/content/changelog/_index.md b/content/changelog/_index.md new file mode 100644 index 00000000..c1c55f6c --- /dev/null +++ b/content/changelog/_index.md @@ -0,0 +1,7 @@ +--- +title: Changelog +type: docs +weight: 1000 +--- + + diff --git a/content/changelog/index.md b/content/changelog/historical.md similarity index 82% rename from content/changelog/index.md rename to content/changelog/historical.md index 560cb43b..72f1d9a2 100644 --- a/content/changelog/index.md +++ b/content/changelog/historical.md @@ -1,18 +1,15 @@ --- -title: Changelog +title: Historical versions type: docs -weight: 1000 +outputs: + - html --- -{{% changelog/changelog-description %}} +Before version 1.1, versioning was applied at the level of individual API specifications. +This section includes links to these versions of the APIs. -{{% changelog/changelogs %}} +## Client-Server API -

Historical versions

- -Before version 1.1, versioning was applied at the level of individual API specifications. This section includes links to these versions of the APIs. - -* **Client-Server API** - [r0.6.1](https://matrix.org/docs/spec/client_server/r0.6.1.html) - [r0.6.0](https://matrix.org/docs/spec/client_server/r0.6.0.html) - [r0.5.0](https://matrix.org/docs/spec/client_server/r0.5.0.html) @@ -26,22 +23,26 @@ Before version 1.1, versioning was applied at the level of individual API specif The last draft before the spec was formally released in version r0.0.0. -* **Server-Server API** +## Server-Server API + - [r0.1.4](https://matrix.org/docs/spec/server_server/r0.1.4.html) - [r0.1.3](https://matrix.org/docs/spec/server_server/r0.1.3.html) - [r0.1.2](https://matrix.org/docs/spec/server_server/r0.1.2.html) - [r0.1.1](https://matrix.org/docs/spec/server_server/r0.1.1.html) - [r0.1.0](https://matrix.org/docs/spec/server_server/r0.1.0.html) -* **Application Service API** +## Application Service API + - [r0.1.1](https://matrix.org/docs/spec/application_service/r0.1.1.html) - [r0.1.0](https://matrix.org/docs/spec/application_service/r0.1.0.html) -* **Identity Service API** +## Identity Service API + - [r0.3.0](https://matrix.org/docs/spec/identity_service/r0.3.0.html) - [r0.2.1](https://matrix.org/docs/spec/identity_service/r0.2.1.html) - [r0.2.0](https://matrix.org/docs/spec/identity_service/r0.2.0.html) - [r0.1.0](https://matrix.org/docs/spec/identity_service/r0.1.0.html) -* **Push Gateway API** +## Push Gateway API + - [r0.1.0](https://matrix.org/docs/spec/push_gateway/r0.1.0.html) diff --git a/content/changelog/v1.1.md b/content/changelog/v1.1.md index 8cf43878..acfc1b21 100644 --- a/content/changelog/v1.1.md +++ b/content/changelog/v1.1.md @@ -1,23 +1,15 @@ --- -date: 2021-11-09T00:00:00+0000 +title: v1.1 Changelog +linkTitle: v1.1 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2021-11-09 --- - - -## v1.1 - - - - -
Git commithttps://github.com/matrix-org/matrix-doc/tree/v1.1
Release dateNovember 09, 2021
- - -### Client-Server API +## Client-Server API Breaking Changes @@ -110,7 +102,7 @@ Variables: - Fix documentation errors around `threepid_creds`. ([#3471](https://github.com/matrix-org/matrix-doc/issues/3471)) -### Server-Server API +## Server-Server API New Endpoints @@ -136,7 +128,7 @@ Variables: - Tweak the example PDU diagram to better demonstrate situations with multiple `prev_events`. ([#3340](https://github.com/matrix-org/matrix-doc/issues/3340)) -### Application Service API +## Application Service API Spec Clarifications @@ -145,7 +137,7 @@ Variables: - Fix various typos throughout the specification. ([#2888](https://github.com/matrix-org/matrix-doc/issues/2888)) -### Identity Service API +## Identity Service API New Endpoints @@ -168,7 +160,7 @@ Variables: - Describe how [MSC2844](https://github.com/matrix-org/matrix-doc/pull/2844) affects the `/versions` endpoint. ([#3459](https://github.com/matrix-org/matrix-doc/issues/3459)) -### Push Gateway API +## Push Gateway API Spec Clarifications diff --git a/content/changelog/v1.10.md b/content/changelog/v1.10.md new file mode 100644 index 00000000..a3115a1f --- /dev/null +++ b/content/changelog/v1.10.md @@ -0,0 +1,93 @@ +--- +title: v1.10 Changelog +linkTitle: v1.10 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2024-03-22 +--- + +## Client-Server API + +**Backwards Compatible Changes** + +- Allow `/versions` to optionally accept authentication, as per [MSC4026](https://github.com/matrix-org/matrix-spec-proposals/pull/4026). ([#1728](https://github.com/matrix-org/matrix-spec/issues/1728)) +- Add local erasure requests, as per [MSC4025](https://github.com/matrix-org/matrix-spec-proposals/pull/4025). ([#1730](https://github.com/matrix-org/matrix-spec/issues/1730)) +- Use the `body` field as optional media caption, as per [MSC2530](https://github.com/matrix-org/matrix-spec-proposals/pull/2530). ([#1731](https://github.com/matrix-org/matrix-spec/issues/1731)) +- Add server support discovery endpoint, as per [MSC1929](https://github.com/matrix-org/matrix-spec-proposals/pull/1929). ([#1733](https://github.com/matrix-org/matrix-spec/issues/1733)) +- Add support for multi-stream VoIP, as per [MSC3077](https://github.com/matrix-org/matrix-spec-proposals/pull/3077). ([#1735](https://github.com/matrix-org/matrix-spec/issues/1735)) +- Specify that the `Retry-After` header may be used to rate-limit a client, as per [MSC4041](https://github.com/matrix-org/matrix-spec-proposals/pull/4041). ([#1737](https://github.com/matrix-org/matrix-spec/issues/1737)) +- Add support for recursion on the `GET /relations` endpoints, as per [MSC3981](https://github.com/matrix-org/matrix-spec-proposals/pull/3981). ([#1746](https://github.com/matrix-org/matrix-spec/issues/1746)) + +**Spec Clarifications** + +- 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. ([#1629](https://github.com/matrix-org/matrix-spec/issues/1629)) +- Clarify that read receipts should be batched by thread as well as by room. ([#1685](https://github.com/matrix-org/matrix-spec/issues/1685)) +- Clarify that threads can be created based on replies. ([#1687](https://github.com/matrix-org/matrix-spec/issues/1687)) +- Clarify in the reply fallbacks example that the prefix sequence should be repeated for each line. ([#1690](https://github.com/matrix-org/matrix-spec/issues/1690)) +- Clarify the format of account data objects for secret storage. ([#1695](https://github.com/matrix-org/matrix-spec/issues/1695), [#1734](https://github.com/matrix-org/matrix-spec/issues/1734)) +- Clarify that the key backup MAC is implemented incorrectly and does not pass the ciphertext through HMAC-SHA-256. ([#1712](https://github.com/matrix-org/matrix-spec/issues/1712)) +- Clarify one-time key and fallback key types in examples. ([#1715](https://github.com/matrix-org/matrix-spec/issues/1715)) +- Clarify that the HKDF calculation for SAS uses base64-encoded keys rather than the raw key bytes. ([#1719](https://github.com/matrix-org/matrix-spec/issues/1719)) +- Clarify how to perform the ECDH exchange in step 12 of the SAS process. ([#1720](https://github.com/matrix-org/matrix-spec/issues/1720)) +- Document the deprecation policy of HTML tags, as per [MSC4077](https://github.com/matrix-org/matrix-spec-proposals/pull/4077). ([#1732](https://github.com/matrix-org/matrix-spec/issues/1732)) +- The [font](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/font) element is deprecated in the HTML spec. Clients should prefer [span](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/span) with the `data-mx-bg-color` and `data-mx-color` attributes instead. ([#1739](https://github.com/matrix-org/matrix-spec/issues/1739)) +- Disambiguate uses of `PublicRoomsChunk` in the `GET /hierarchy` endpoint. ([#1740](https://github.com/matrix-org/matrix-spec/issues/1740)) +- Clarify that `sdpMid` and `sdpMLineIndex` are not required in `m.call.candidates`. ([#1742](https://github.com/matrix-org/matrix-spec/issues/1742)) +- Fix various typos throughout the specification. ([#1748](https://github.com/matrix-org/matrix-spec/issues/1748)) +- Clearly indicate that each `Content-Type` may have distinct behaviour on non-JSON requests/responses. ([#1756](https://github.com/matrix-org/matrix-spec/issues/1756)) +- Clarify that the `m.push_rules` account data type cannot be set using the `/account_data` API, as per [MSC4010](https://github.com/matrix-org/matrix-spec-proposals/pull/4010). ([#1763](https://github.com/matrix-org/matrix-spec/issues/1763)) + + +## Server-Server API + +**Spec Clarifications** + +- Clarify Server-Server API request signing example by using the `POST` HTTP method, as `GET` requests don't have request bodies. ([#1721](https://github.com/matrix-org/matrix-spec/issues/1721)) +- Disambiguate uses of `PublicRoomsChunk` in the `GET /hierarchy` endpoint. ([#1740](https://github.com/matrix-org/matrix-spec/issues/1740)) +- Clarify that the `children_state`, `room_type` and `allowed_room_ids` properties in the items of the `children` array of the response of the `GET /hierarchy` endpoint are not required. ([#1741](https://github.com/matrix-org/matrix-spec/issues/1741)) + + +## Application Service API + +**Spec Clarifications** + +- Clarify that the `/login` and `/register` endpoints should fail when using the `m.login.application_service` login type without a valid `as_token`. ([#1744](https://github.com/matrix-org/matrix-spec/issues/1744)) + + +## Identity Service API + +No significant changes. + + +## Push Gateway API + +No significant changes. + + +## Room Versions + +**Spec Clarifications** + +- For room versions 7 through 11: Clarify that `invite->knock` is not a legal transition. ([#1717](https://github.com/matrix-org/matrix-spec/issues/1717)) + + +## Appendices + +No significant changes. + + +## Internal Changes/Tooling + +**Spec Clarifications** + +- Update the spec release process. ([#1680](https://github.com/matrix-org/matrix-spec/issues/1680)) +- Minor clarifications to the contributing guide. ([#1697](https://github.com/matrix-org/matrix-spec/issues/1697)) +- Update Docsy to v0.8.0. ([#1699](https://github.com/matrix-org/matrix-spec/issues/1699), [#1762](https://github.com/matrix-org/matrix-spec/issues/1762)) +- Fix npm release script for `@matrix-org/spec`. ([#1713](https://github.com/matrix-org/matrix-spec/issues/1713)) +- Add some clarifications around implementation requirements for MSCs. ([#1718](https://github.com/matrix-org/matrix-spec/issues/1718)) +- Update HTML templates to include links to object schema definitions. ([#1724](https://github.com/matrix-org/matrix-spec/issues/1724)) +- Factor out all the common parameters of the various `/relations` apis. ([#1745](https://github.com/matrix-org/matrix-spec/issues/1745)) +- Add support for `$ref` URIs containing fragments in OpenAPI definitions and JSON schemas. ([#1751](https://github.com/matrix-org/matrix-spec/issues/1751), [#1754](https://github.com/matrix-org/matrix-spec/issues/1754)) diff --git a/content/changelog/v1.11.md b/content/changelog/v1.11.md new file mode 100644 index 00000000..7f12c1e3 --- /dev/null +++ b/content/changelog/v1.11.md @@ -0,0 +1,161 @@ +--- +title: v1.11 Changelog +linkTitle: v1.11 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2024-06-20 +--- + +## Client-Server API + +**Deprecations** + +- Authentication using a query string is now deprecated, as per [MSC4126](https://github.com/matrix-org/matrix-spec-proposals/issues/4126). The `Authorization` header should be used instead. ([#1808](https://github.com/matrix-org/matrix-spec/issues/1808)) +- Use of the `/_matrix/media/*` endpoints is now deprecated. New, authenticated, endpoints are available instead. ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) + +**New Endpoints** + +- [`GET /_matrix/client/v1/media/config`](/client-server-api/#get_matrixclientv1mediaconfig) ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) +- [`GET /_matrix/client/v1/media/download/{serverName}/{mediaId}`](/client-server-api/#get_matrixclientv1mediadownloadservernamemediaid) ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) +- [`GET /_matrix/client/v1/media/download/{serverName}/{mediaId}/{fileName}`](/client-server-api/#get_matrixclientv1mediadownloadservernamemediaidfilename) ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) +- [`GET /_matrix/client/v1/media/preview_url`](/client-server-api/#get_matrixclientv1mediapreview_url) ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) +- [`GET /_matrix/client/v1/media/thumbnail/{serverName}/{mediaId}`](/client-server-api/#get_matrixclientv1mediathumbnailservernamemediaid) ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) + +**Backwards Compatible Changes** + +- Add support for muting in VoIP calls, as per [MSC3291](https://github.com/matrix-org/matrix-spec-proposals/pull/3291). ([#1755](https://github.com/matrix-org/matrix-spec/issues/1755)) +- Add optional `animated` query string option to `GET /thumbnail`, as per [MSC2705](https://github.com/matrix-org/matrix-spec-proposals/pull/2705). ([#1757](https://github.com/matrix-org/matrix-spec/issues/1757)) +- Specify terms of services at registration, as per [MSC1692](https://github.com/matrix-org/matrix-spec-proposals/pull/1692). ([#1812](https://github.com/matrix-org/matrix-spec/issues/1812)) +- Add support for mathematical messages, as per [MSC2191](https://github.com/matrix-org/matrix-spec-proposals/pull/2191). ([#1816](https://github.com/matrix-org/matrix-spec/issues/1816)) +- Do not require UIA when first uploading cross-signing keys, as per [MSC3967](https://github.com/matrix-org/matrix-spec-proposals/pull/3967). ([#1828](https://github.com/matrix-org/matrix-spec/issues/1828)) +- Add the new `unsigned.membership` property to events, as per [MSC4115](https://github.com/matrix-org/matrix-spec-proposals/pull/4115). ([#1847](https://github.com/matrix-org/matrix-spec/issues/1847)) +- Media downloads and thumbnails are now authenticated, as per [MSC3916](https://github.com/matrix-org/matrix-spec-proposals/pull/3916). ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) +- Some media endpoints are now consistently under `/_matrix/client/{version}/media/*` instead of `/_matrix/media/*`, as per [MSC3916](https://github.com/matrix-org/matrix-spec-proposals/pull/3916). ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) + +**Spec Clarifications** + +- Add `/logout` and clarify the endpoints which do not take a JSON request body. ([#1644](https://github.com/matrix-org/matrix-spec/issues/1644)) +- Clarify that the `type` of the `POST /login` request must be one of the types returned by the `GET /login` response. ([#1776](https://github.com/matrix-org/matrix-spec/issues/1776)) +- Link to existing grammar where possible in types. ([#1813](https://github.com/matrix-org/matrix-spec/issues/1813)) +- Rename "recovery key" to "backup decryption key". ([#1819](https://github.com/matrix-org/matrix-spec/issues/1819)) +- Clarify that the device's Ed25519 signing key should be used in QR code verification (as opposed to the device's Curve25519 identity key). ([#1829](https://github.com/matrix-org/matrix-spec/issues/1829)) +- Fix various typos throughout the specification. ([#1832](https://github.com/matrix-org/matrix-spec/issues/1832), [#1841](https://github.com/matrix-org/matrix-spec/issues/1841), [#1852](https://github.com/matrix-org/matrix-spec/issues/1852), [#1853](https://github.com/matrix-org/matrix-spec/issues/1853)) +- Specify the encoding to be used when generating QR codes for device verification. ([#1839](https://github.com/matrix-org/matrix-spec/issues/1839)) +- Clarify that an access token is optional on the `POST /account/password` and `POST /account/deactivate` endpoints. ([#1843](https://github.com/matrix-org/matrix-spec/issues/1843)) +- Use RFC 2119 keywords more consistently. ([#1846](https://github.com/matrix-org/matrix-spec/issues/1846), [#1861](https://github.com/matrix-org/matrix-spec/issues/1861)) +- Move size limits for user, room and event IDs into the appendix and clarify that the length is to be measured in bytes. ([#1850](https://github.com/matrix-org/matrix-spec/issues/1850)) +- Clarify that relations recursion should be capped at a certain depth. ([#1854](https://github.com/matrix-org/matrix-spec/issues/1854)) +- Add missing secrets, third-party invites and room tagging modules to feature profiles table. ([#1860](https://github.com/matrix-org/matrix-spec/issues/1860)) +- Clarify when server name is used and link to the definition. ([#1862](https://github.com/matrix-org/matrix-spec/issues/1862)) +- Clarify where keys reside when checking an `m.room.encrypted` event. ([#1863](https://github.com/matrix-org/matrix-spec/issues/1863)) +- Clarify that `/media/v3/upload/{serverName}/{mediaId}` requires authentication. ([#1872](https://github.com/matrix-org/matrix-spec/issues/1872)) + + +## Server-Server API + +**Deprecations** + +- Use of the Client-Server API `/_matrix/media/*` endpoints is now deprecated. New, authenticated, endpoints are available instead. ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) + +**New Endpoints** + +- [`GET /_matrix/federation/v1/media/download/{mediaId}`](/server-server-api/#get_matrixfederationv1mediadownloadmediaid) ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) +- [`GET /_matrix/federation/v1/media/thumbnail/{mediaId}`](/server-server-api/#get_matrixfederationv1mediathumbnailmediaid) ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858)) + +**Backwards Compatible Changes** + +- Media downloads and thumbnails are now authenticated, as per [MSC3916](https://github.com/matrix-org/matrix-spec-proposals/pull/3916). ([#1858](https://github.com/matrix-org/matrix-spec/issues/1858), [#1869](https://github.com/matrix-org/matrix-spec/issues/1869)) + +**Spec Clarifications** + +- Link to existing grammar where possible in types. ([#1813](https://github.com/matrix-org/matrix-spec/issues/1813)) +- Clarify that whitespace around commas is allowed in the `X-Matrix` `Authorization` header value params list. ([#1818](https://github.com/matrix-org/matrix-spec/issues/1818)) +- Clarify that the `event` field of the `/v2/send_join` response is only required when the event is signed by the resident server. ([#1834](https://github.com/matrix-org/matrix-spec/issues/1834), [#1840](https://github.com/matrix-org/matrix-spec/issues/1840)) +- Replace references to RFC 7235 and RFC 7230 that are obsoleted by RFC 9110. ([#1844](https://github.com/matrix-org/matrix-spec/issues/1844)) +- Fix various typos throughout the specification. ([#1877](https://github.com/matrix-org/matrix-spec/issues/1877)) + + +## Application Service API + +**Spec Clarifications** + +- Clarify that appservices should be notified of events relating to the `sender_localpart` user. ([#1810](https://github.com/matrix-org/matrix-spec/issues/1810)) + + +## Identity Service API + +**Deprecations** + +- Authentication using a query string is now deprecated, as per [MSC4126](https://github.com/matrix-org/matrix-spec-proposals/issues/4126). The `Authorization` header should be used instead. ([#1808](https://github.com/matrix-org/matrix-spec/issues/1808)) + + +## Push Gateway API + +No significant changes. + + +## Room Versions + +**Spec Clarifications** + +- Clarify that redaction events are still subject to all applicable auth rules. ([#1824](https://github.com/matrix-org/matrix-spec/issues/1824)) +- Fix various typos throughout the specification. ([#1827](https://github.com/matrix-org/matrix-spec/issues/1827), [#1848](https://github.com/matrix-org/matrix-spec/issues/1848)) +- Fix the rendering of the event format for room versions 1 and 2. ([#1883](https://github.com/matrix-org/matrix-spec/issues/1883)) +- Generate the Table of Contents with Hugo rather than JavaScript. ([#1884](https://github.com/matrix-org/matrix-spec/issues/1884)) + + +## Appendices + +**Deprecations** + +- Deprecate linking to events in rooms identified by alias, as per [MSC4132](https://github.com/matrix-org/matrix-spec-proposals/pull/4132). ([#1823](https://github.com/matrix-org/matrix-spec/issues/1823)) + +**Spec Clarifications** + +- Define 'Opaque Identifier Grammar'. ([#1791](https://github.com/matrix-org/matrix-spec/issues/1791)) +- Define common cryptographic key representation. ([#1819](https://github.com/matrix-org/matrix-spec/issues/1819)) +- Move size limits for user, room and event IDs into the appendix and clarify that the length is to be measured in bytes. ([#1850](https://github.com/matrix-org/matrix-spec/issues/1850)) + + +## Internal Changes/Tooling + +**Spec Clarifications** + +- Update the spec release process and related documentation. ([#1759](https://github.com/matrix-org/matrix-spec/issues/1759)) +- Fix npm release script for `@matrix-org/spec`. ([#1765](https://github.com/matrix-org/matrix-spec/issues/1765)) +- Formatting fixes in `CONTRIBUTING.rst`. ([#1769](https://github.com/matrix-org/matrix-spec/issues/1769)) +- Improve rendering on mobile devices. ([#1770](https://github.com/matrix-org/matrix-spec/issues/1770), [#1771](https://github.com/matrix-org/matrix-spec/issues/1771)) +- Fix the OpenAPI definition of the security schemes. ([#1772](https://github.com/matrix-org/matrix-spec/issues/1772)) +- Simplify uses of `resolve-refs` partial. ([#1773](https://github.com/matrix-org/matrix-spec/issues/1773)) +- Fix Hugo warnings. ([#1775](https://github.com/matrix-org/matrix-spec/issues/1775), [#1788](https://github.com/matrix-org/matrix-spec/issues/1788)) +- Fix `github-labels.rst`. ([#1781](https://github.com/matrix-org/matrix-spec/issues/1781)) +- Update dependencies. ([#1786](https://github.com/matrix-org/matrix-spec/issues/1786), [#1803](https://github.com/matrix-org/matrix-spec/issues/1803), [#1804](https://github.com/matrix-org/matrix-spec/issues/1804)) +- Solve `allOf` recursively in OpenAPI and JSON Schemas. ([#1787](https://github.com/matrix-org/matrix-spec/issues/1787)) +- Fix property type resolution in `render-object-table` partial. ([#1789](https://github.com/matrix-org/matrix-spec/issues/1789)) +- Factor out common definition of `Tag` type. ([#1793](https://github.com/matrix-org/matrix-spec/issues/1793)) +- Update the version of Hugo used to render the spec to v0.124.1. ([#1794](https://github.com/matrix-org/matrix-spec/issues/1794)) +- Add support for pattern formats for `patternProperties`. ([#1796](https://github.com/matrix-org/matrix-spec/issues/1796)) +- Clean up unnecessary `allOf`s in OpenAPI definitions. ([#1797](https://github.com/matrix-org/matrix-spec/issues/1797)) +- Show information about "Additional Properties" in object tables. ([#1798](https://github.com/matrix-org/matrix-spec/issues/1798)) +- Fix anchors for schemas under `oneOf`. ([#1799](https://github.com/matrix-org/matrix-spec/issues/1799)) +- Use reference to `OneTimeKeys` schema in OpenAPI definitions. ([#1800](https://github.com/matrix-org/matrix-spec/issues/1800)) +- Do not use the `title` of objects containing only `additionalProperties` or `patternProperties`. ([#1801](https://github.com/matrix-org/matrix-spec/issues/1801)) +- Add anchors in `definition` shortcode. ([#1802](https://github.com/matrix-org/matrix-spec/issues/1802)) +- Set python version for the Towncrier CI job. ([#1805](https://github.com/matrix-org/matrix-spec/issues/1805)) +- Replace `set-output` with environment files in CI. ([#1806](https://github.com/matrix-org/matrix-spec/issues/1806)) +- Render response headers. ([#1809](https://github.com/matrix-org/matrix-spec/issues/1809)) +- Use `patternProperties` in more places with supported formats. ([#1813](https://github.com/matrix-org/matrix-spec/issues/1813)) +- Add support for rendering string formats. ([#1814](https://github.com/matrix-org/matrix-spec/issues/1814)) +- Refactor the OpenAPI definitions of the content repository endpoints. ([#1822](https://github.com/matrix-org/matrix-spec/issues/1822)) +- Clean up pull request template. ([#1831](https://github.com/matrix-org/matrix-spec/issues/1831)) +- Do not add empty arrays to examples. ([#1849](https://github.com/matrix-org/matrix-spec/issues/1849)) +- Generate the Table of Contents with Hugo rather than JavaScript. ([#1851](https://github.com/matrix-org/matrix-spec/issues/1851), [#1885](https://github.com/matrix-org/matrix-spec/issues/1885)) +- Fix syntax errors in the spec release issue template. ([#1856](https://github.com/matrix-org/matrix-spec/issues/1856)) +- Use environment variables for Netlify build job. ([#1865](https://github.com/matrix-org/matrix-spec/issues/1865)) +- Render added/changed in info on request and response content types. ([#1876](https://github.com/matrix-org/matrix-spec/issues/1876)) +- Fix validation errors in generated HTML. ([#1880](https://github.com/matrix-org/matrix-spec/issues/1880)) +- Ensure most generated HTML IDs are unique. ([#1881](https://github.com/matrix-org/matrix-spec/issues/1881)) +- Allow to specify a prefix for generated HTML IDs of API endpoints. ([#1882](https://github.com/matrix-org/matrix-spec/issues/1882)) diff --git a/content/changelog/v1.12.md b/content/changelog/v1.12.md new file mode 100644 index 00000000..4f4f65dd --- /dev/null +++ b/content/changelog/v1.12.md @@ -0,0 +1,113 @@ +--- +title: v1.12 Changelog +linkTitle: v1.12 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2024-10-07 +--- + +## Client-Server API + +**Deprecations** + +- Deprecate the `server_name` query parameter on `POST /_matrix/client/v3/join/{roomIdOrAlias}` and `POST /_matrix/client/v3/knock/{roomIdOrAlias}`, as per [MSC4156](https://github.com/matrix-org/matrix-spec-proposals/pull/4156). ([#1933](https://github.com/matrix-org/matrix-spec/issues/1933)) + +**Removed Endpoints** + +- Remove references to device-specific push rules. ([#1842](https://github.com/matrix-org/matrix-spec/issues/1842)) +- Remove the deprecated name attribute on HTML anchor elements, as per [MSC4159](https://github.com/matrix-org/matrix-spec-proposals/pull/4159). ([#1870](https://github.com/matrix-org/matrix-spec/issues/1870)) + +**Backwards Compatible Changes** + +- Add 403 responses on `GET /_matrix/client/v3/profile/{userId}/avatar_url` and `GET /_matrix/client/v3/profile/{userId}/displayname`, as per [MSC4170](https://github.com/matrix-org/matrix-spec-proposals/pull/4170). ([#1867](https://github.com/matrix-org/matrix-spec/issues/1867)) +- Add support for marking rooms as unread, as per [MSC2867](https://github.com/matrix-org/matrix-spec-proposals/pull/2867). ([#1895](https://github.com/matrix-org/matrix-spec/issues/1895), [#1941](https://github.com/matrix-org/matrix-spec/issues/1941)) +- Add `via` query parameter on `POST /_matrix/client/v3/join/{roomIdOrAlias}` and `POST /_matrix/client/v3/knock/{roomIdOrAlias}`, as per [MSC4156](https://github.com/matrix-org/matrix-spec-proposals/pull/4156). ([#1933](https://github.com/matrix-org/matrix-spec/issues/1933)) +- Add account locking, as per [MSC3939](https://github.com/matrix-org/matrix-spec-proposals/pull/3939). ([#1934](https://github.com/matrix-org/matrix-spec/issues/1934)) +- Guest accounts can now download/thumbnail media from the new authenticated endpoints, as per [MSC4189](https://github.com/matrix-org/matrix-spec-proposals/pull/4189). ([#1959](https://github.com/matrix-org/matrix-spec/issues/1959)) + +**Spec Clarifications** + +- Rename and sort the modules in the feature profiles table for easier skimming. ([#1855](https://github.com/matrix-org/matrix-spec/issues/1855)) +- Clarify that room avatars cannot be encrypted. ([#1871](https://github.com/matrix-org/matrix-spec/issues/1871)) +- Document the acronyms and alternate names for the "Secrets" section. ([#1875](https://github.com/matrix-org/matrix-spec/issues/1875)) +- Improve recommendation for how to form transaction IDs. ([#1888](https://github.com/matrix-org/matrix-spec/issues/1888)) +- Clarify that the deprecated `dont_notify` and `coalesce` push rule actions MUST be ignored, not rejected. ([#1890](https://github.com/matrix-org/matrix-spec/issues/1890)) +- Fix various typos throughout the specification. ([#1892](https://github.com/matrix-org/matrix-spec/issues/1892)) +- Add missing references to `m.set_displayname`, `m.set_avatar_url`, and `m.3pid_changes` in capabilities table. ([#1897](https://github.com/matrix-org/matrix-spec/issues/1897)) +- Clarify that the fallback login page calls `window.matrixLogin.onLogin` instead of `window.onLogin`. ([#1899](https://github.com/matrix-org/matrix-spec/issues/1899)) +- Remove confusing description of restricted rooms with no valid conditions. ([#1903](https://github.com/matrix-org/matrix-spec/issues/1903)) +- Clarify that `window.matrixLogin.onLogin` is called with the response body of `POST /_matrix/client/v3/login`. ([#1905](https://github.com/matrix-org/matrix-spec/issues/1905)) +- Document the `m.get_login_token` capability, as per [MSC3882](https://github.com/matrix-org/matrix-spec-proposals/pull/3882). ([#1908](https://github.com/matrix-org/matrix-spec/issues/1908)) +- Clarify that the `User identifier` object in `POST /_matrix/client/v3/login` contains additional properties that depend on the identification type. ([#1909](https://github.com/matrix-org/matrix-spec/issues/1909)) +- Don't mention that `GET /_matrix/client/v3/profile/{userId}` can return additional properties because this is true for almost every endpoint. ([#1910](https://github.com/matrix-org/matrix-spec/issues/1910)) +- Improve wording of the unauthenticated media deprecation box. Contributed by @HarHarLinks. ([#1916](https://github.com/matrix-org/matrix-spec/issues/1916)) +- Additional properties in `GET /.well-known/matrix/client` don't have to be objects. ([#1920](https://github.com/matrix-org/matrix-spec/issues/1920)) +- Document that the spec uses [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) keywords. Contributed by @HarHarLinks. ([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) +- Specify `Content-Type` and `Content-Disposition` usage in the media repo, as per [MSC2701](https://github.com/matrix-org/matrix-spec-proposals/pull/2701) and [MSC2702](https://github.com/matrix-org/matrix-spec-proposals/pull/2702). ([#1935](https://github.com/matrix-org/matrix-spec/issues/1935)) +- Additional keys in `GET /_matrix/client/v3/capabilities` don't have to be objects. ([#1945](https://github.com/matrix-org/matrix-spec/issues/1945)) + + +## Server-Server API + +**Backwards Compatible Changes** + +- Add 403 response on `GET /_matrix/federation/v1/query/profile`, as per [MSC4170](https://github.com/matrix-org/matrix-spec-proposals/pull/4170). ([#1867](https://github.com/matrix-org/matrix-spec/issues/1867)) + +**Spec Clarifications** + +- Remove `origin` field from PDU example because it doesn't exist in the schema anymore. ([#1918](https://github.com/matrix-org/matrix-spec/issues/1918)) +- Document that the spec uses [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) keywords. Contributed by @HarHarLinks. ([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) +- Fix required fields in `GET /_matrix/key/v2/server` response schema. ([#1930](https://github.com/matrix-org/matrix-spec/issues/1930)) +- Use "server name" instead of "DNS name" to avoid confusion with the "DNS name" component of "server names" as defined in the appendices. ([#1946](https://github.com/matrix-org/matrix-spec/issues/1946)) + + +## Application Service API + +**Spec Clarifications** + +- Document that the spec uses [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) keywords. Contributed by @HarHarLinks. ([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) + + +## Identity Service API + +**Spec Clarifications** + +- Document that the spec uses [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) keywords. Contributed by @HarHarLinks. ([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) + + +## Push Gateway API + +**Spec Clarifications** + +- Document that the spec uses [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) keywords. Contributed by @HarHarLinks. ([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) + + +## Room Versions + +**Spec Clarifications** + +- Fix a formatting issue in state resolution v2. ([#1896](https://github.com/matrix-org/matrix-spec/issues/1896)) +- Document that the spec uses [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) keywords. Contributed by @HarHarLinks. ([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) + + +## Appendices + +**Spec Clarifications** + +- Document that the spec uses [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) keywords. Contributed by @HarHarLinks. ([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) + + +## Internal Changes/Tooling + +**Spec Clarifications** + +- The Matrix.org Foundation no longer requires "real" or "legally identifiable" names in order to contribute to projects. ([#1886](https://github.com/matrix-org/matrix-spec/issues/1886), [#1914](https://github.com/matrix-org/matrix-spec/issues/1914)) +- Document the `removal` changelog category. ([#1907](https://github.com/matrix-org/matrix-spec/issues/1907)) +- Use dedicated fonts for better support of mathematical symbols. ([#1919](https://github.com/matrix-org/matrix-spec/issues/1919)) +- Document that the spec uses [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) keywords. Contributed by @HarHarLinks. ([#1928](https://github.com/matrix-org/matrix-spec/issues/1928)) +- Provide markdown checklists for changelogs under `/changelog/$VERSION/checklist.md`. ([#1937](https://github.com/matrix-org/matrix-spec/issues/1937), [#1954](https://github.com/matrix-org/matrix-spec/issues/1954)) +- Add the `deprecated` field to properties of OpenAPI definitions and JSON Schemas. ([#1940](https://github.com/matrix-org/matrix-spec/issues/1940)) +- Use relative permalink to redirect to latest changelog. ([#1956](https://github.com/matrix-org/matrix-spec/issues/1956)) diff --git a/content/changelog/v1.13.md b/content/changelog/v1.13.md new file mode 100644 index 00000000..df91175b --- /dev/null +++ b/content/changelog/v1.13.md @@ -0,0 +1,108 @@ +--- +title: v1.13 Changelog +linkTitle: v1.13 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2024-12-19 +--- + +## Client-Server API + +**New Endpoints** + +- Add `POST /_matrix/client/v3/rooms/{roomId}/report`, as per [MSC4151](https://github.com/matrix-org/matrix-spec-proposals/pull/4151). ([#1938](https://github.com/matrix-org/matrix-spec/issues/1938), [#2028](https://github.com/matrix-org/matrix-spec/issues/2028)) + +**Backwards Compatible Changes** + +- Add error codes to requestToken endpoints, as per [MSC4178](https://github.com/matrix-org/matrix-spec-proposals/pull/4178). ([#1944](https://github.com/matrix-org/matrix-spec/issues/1944)) +- Remove reply fallbacks, as per [MSC2781](https://github.com/matrix-org/matrix-spec-proposals/issues/2781). ([#1994](https://github.com/matrix-org/matrix-spec/issues/1994)) +- Clarify the allowed HTTP methods in CORS responses, as per [MSC4138](https://github.com/matrix-org/matrix-spec-proposals/pull/4138). ([#1995](https://github.com/matrix-org/matrix-spec/issues/1995), [#2011](https://github.com/matrix-org/matrix-spec/issues/2011)) +- Add new `M_USER_SUSPENDED` error code behaviour, as per [MSC3823](https://github.com/matrix-org/matrix-spec-proposals/pull/3823). ([#2014](https://github.com/matrix-org/matrix-spec/issues/2014)) + +**Spec Clarifications** + +- The `reason` parameter in `POST /_matrix/client/v3/rooms/{roomId}/report/{eventId}` can be omitted instead of left blank, as per [MSC2414](https://github.com/matrix-org/matrix-spec-proposals/pull/2414). ([#1938](https://github.com/matrix-org/matrix-spec/issues/1938)) +- Correct OpenAPI specification for query parameters to `GET /_matrix/client/v3/thirdparty/location/{protocol}` endpoint. ([#1947](https://github.com/matrix-org/matrix-spec/issues/1947)) +- Sort VoIP events semantically. ([#1967](https://github.com/matrix-org/matrix-spec/issues/1967)) +- Clarify that servers must forward custom keys in `PusherData` when sending notifications to the push gateway. ([#1973](https://github.com/matrix-org/matrix-spec/issues/1973)) +- Clarify formats of string types. ([#1978](https://github.com/matrix-org/matrix-spec/issues/1978), [#1979](https://github.com/matrix-org/matrix-spec/issues/1979), [#1980](https://github.com/matrix-org/matrix-spec/issues/1980)) +- Clarify that the async upload endpoint will return 404 in some cases. ([#1983](https://github.com/matrix-org/matrix-spec/issues/1983)) +- Remove distinction between `StateFilter` and `RoomEventFilter`. ([#2015](https://github.com/matrix-org/matrix-spec/issues/2015)) +- Add hyperlinks throughout the specification. ([#2016](https://github.com/matrix-org/matrix-spec/issues/2016)) +- Use `json` instead of `json5` for syntax highlighting. ([#2017](https://github.com/matrix-org/matrix-spec/issues/2017)) +- Specify order that one-time keys are issued by `/keys/claim`, as per [MSC4225](https://github.com/matrix-org/matrix-spec-proposals/pull/4225). ([#2029](https://github.com/matrix-org/matrix-spec/issues/2029)) + + +## Server-Server API + +**Backwards Compatible Changes** + +- Make ACLs apply to EDUs, as per [MSC4163](https://github.com/matrix-org/matrix-spec-proposals/pull/4163). ([#2004](https://github.com/matrix-org/matrix-spec/issues/2004)) + +**Spec Clarifications** + +- Add 403 error response to `/_matrix/federation/v1/state_ids/{roomId}`. ([#1926](https://github.com/matrix-org/matrix-spec/issues/1926)) + + +## Application Service API + +**Backwards Compatible Changes** + +- Allow sending ephemeral data to application services, as per [MSC2409](https://github.com/matrix-org/matrix-spec-proposals/pull/2409). ([#2018](https://github.com/matrix-org/matrix-spec/issues/2018)) + + +## Identity Service API + +No significant changes. + + +## Push Gateway API + +**Spec Clarifications** + +- Document the schema of `PusherData`. ([#1968](https://github.com/matrix-org/matrix-spec/issues/1968)) +- The path of HTTP pusher URLs is fixed to `/_matrix/push/v1/notify`. ([#1974](https://github.com/matrix-org/matrix-spec/issues/1974)) + + +## Room Versions + +**Spec Clarifications** + +- Clarify rule 4.3.1 of the auth rules in room version 11 to state which event's `sender` the `state_key` needs to match. ([#2024](https://github.com/matrix-org/matrix-spec/issues/2024)) + + +## Appendices + +**Spec Clarifications** + +- Remove note about reference implementations. ([#1966](https://github.com/matrix-org/matrix-spec/issues/1966)) + + +## Internal Changes/Tooling + +**Spec Clarifications** + +- Add `x-weight` property for sorting events rendered with the `event-group` shortcode. ([#1967](https://github.com/matrix-org/matrix-spec/issues/1967)) +- Enforce consistent vertical spacing between paragraphs in endpoint definitions. ([#1969](https://github.com/matrix-org/matrix-spec/issues/1969), [#2005](https://github.com/matrix-org/matrix-spec/issues/2005)) +- Remove `boxes/added-in-paragraph` shortcode. ([#1970](https://github.com/matrix-org/matrix-spec/issues/1970)) +- Remove `withVersioning` parameter of `rver-fragment` shortcode. ([#1971](https://github.com/matrix-org/matrix-spec/issues/1971)) +- Remove `span` element from `added-in` and `changed-in` shortcodes. ([#1972](https://github.com/matrix-org/matrix-spec/issues/1972)) +- Fix formatting of `added-in` and `changed-in` shortcodes by using `%` delimiter. ([#1975](https://github.com/matrix-org/matrix-spec/issues/1975)) +- Remove CSS workaround for scroll-anchoring. ([#1976](https://github.com/matrix-org/matrix-spec/issues/1976)) +- Rename `custom-formats.yaml` to `string-formats.yaml` and update its docs. ([#1977](https://github.com/matrix-org/matrix-spec/issues/1977)) +- Fix relative URLs when serving the specification with a custom `baseURL`. ([#1984](https://github.com/matrix-org/matrix-spec/issues/1984), [#1997](https://github.com/matrix-org/matrix-spec/issues/1997)) +- Rename `.htmltest.yaml` to `.htmltest.yml`. ([#1985](https://github.com/matrix-org/matrix-spec/issues/1985)) +- Improve the JS script to highlight the current ToC entry. ([#1991](https://github.com/matrix-org/matrix-spec/issues/1991), [#2002](https://github.com/matrix-org/matrix-spec/issues/2002)) +- Upgrade docsy to 0.11.0 and hugo to 0.139.0. ([#1996](https://github.com/matrix-org/matrix-spec/issues/1996), [#2007](https://github.com/matrix-org/matrix-spec/issues/2007)) +- Improve the quality of the rendered diagrams ([#1999](https://github.com/matrix-org/matrix-spec/issues/1999)) +- Update the Inter font and allow the browser to render the page before it is loaded ([#2000](https://github.com/matrix-org/matrix-spec/issues/2000)) +- Use a proper Matrix favicon ([#2001](https://github.com/matrix-org/matrix-spec/issues/2001)) +- Clean up unused CSS classes in `openapi/render-operation` partial. ([#2003](https://github.com/matrix-org/matrix-spec/issues/2003)) +- Fix `changed-in` partial when used with multiple paragraphs. ([#2006](https://github.com/matrix-org/matrix-spec/issues/2006)) +- Optimize generated CSS by removing unused selectors. ([#2008](https://github.com/matrix-org/matrix-spec/issues/2008)) +- Remove trailing slash on void HTML elements. ([#2009](https://github.com/matrix-org/matrix-spec/issues/2009)) +- Remove `type` and `language` attributes of `script` element. ([#2021](https://github.com/matrix-org/matrix-spec/issues/2021)) +- Change the accessible role of info boxes to `note`. ([#2022](https://github.com/matrix-org/matrix-spec/issues/2022)) diff --git a/content/changelog/v1.2.md b/content/changelog/v1.2.md index 22deb1ac..9fd35eb5 100644 --- a/content/changelog/v1.2.md +++ b/content/changelog/v1.2.md @@ -1,23 +1,15 @@ --- -date: 2022-02-02T00:00:00+0000 +title: v1.2 Changelog +linkTitle: v1.2 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2022-02-02 --- - - -## v1.2 - - - - -
Git commithttps://github.com/matrix-org/matrix-doc/tree/v1.2
Release dateFebruary 02, 2022
- - -### Client-Server API +## Client-Server API Breaking Changes @@ -65,7 +57,7 @@ Variables: - Fix the rendering of the responses for various API endpoints. ([#3674](https://github.com/matrix-org/matrix-doc/issues/3674)) -### Server-Server API +## Server-Server API New Endpoints @@ -88,7 +80,7 @@ Variables: - Fix the rendering of the responses for various API endpoints. ([#3674](https://github.com/matrix-org/matrix-doc/issues/3674)) -### Application Service API +## Application Service API Spec Clarifications @@ -99,7 +91,7 @@ Variables: - Correct the documentation for the response value for `GET /_matrix/app/v1/thirdparty/protocol/{protocol}`. ([#3675](https://github.com/matrix-org/matrix-doc/issues/3675)) -### Identity Service API +## Identity Service API Backwards Compatible Changes @@ -114,7 +106,7 @@ Variables: - Fix the rendering of the responses for various API endpoints. ([#3674](https://github.com/matrix-org/matrix-doc/issues/3674)) -### Push Gateway API +## Push Gateway API Spec Clarifications @@ -123,7 +115,7 @@ Variables: - Fix the rendering of the responses for various API endpoints. ([#3674](https://github.com/matrix-org/matrix-doc/issues/3674)) -### Room Versions +## Room Versions Backwards Compatible Changes @@ -144,7 +136,7 @@ Variables: - Fix auth rules to allow membership of `knock` -> `leave` in v7, v8, and v9. ([#3694](https://github.com/matrix-org/matrix-doc/issues/3694)) -### Appendices +## Appendices Backwards Compatible Changes diff --git a/content/changelog/v1.3.md b/content/changelog/v1.3.md index bc05b1cc..270783e7 100644 --- a/content/changelog/v1.3.md +++ b/content/changelog/v1.3.md @@ -1,23 +1,15 @@ --- -date: 2022-06-15T00:00:00+0100 +title: v1.3 Changelog +linkTitle: v1.3 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2022-06-15 --- - - -## v1.3 - - - - -
Git commithttps://github.com/matrix-org/matrix-spec/tree/v1.3
Release dateJune 15, 2022
- - -### Client-Server API +## Client-Server API Deprecations @@ -55,7 +47,7 @@ Variables: - Fix membership state transitions to denote that `invite->knock` and `external->leave` are valid transitions. ([#3730](https://github.com/matrix-org/matrix-spec-proposals/issues/3730)) -### Server-Server API +## Server-Server API Backwards Compatible Changes @@ -79,7 +71,7 @@ Variables: - Clarify that the `content` for `X-Matrix` signature validation is the parsed JSON body. ([#3727](https://github.com/matrix-org/matrix-spec-proposals/issues/3727)) -### Application Service API +## Application Service API Backwards Compatible Changes @@ -88,19 +80,19 @@ Variables: - Add timestamp massaging as per [MSC3316](https://github.com/matrix-org/matrix-spec-proposals/pull/3316). ([#1094](https://github.com/matrix-org/matrix-spec/issues/1094)) -### Identity Service API +## Identity Service API No significant changes. -### Push Gateway API +## Push Gateway API No significant changes. -### Room Versions +## Room Versions Backwards Compatible Changes @@ -124,7 +116,7 @@ No significant changes. - For room versions 7, 8, 9, and 10: fix join membership authorization rules when `join_rule` is `knock`. ([#3737](https://github.com/matrix-org/matrix-spec-proposals/issues/3737)) -### Appendices +## Appendices No significant changes. diff --git a/content/changelog/v1.4.md b/content/changelog/v1.4.md index 7d22c00e..febb3874 100644 --- a/content/changelog/v1.4.md +++ b/content/changelog/v1.4.md @@ -1,23 +1,15 @@ --- -date: 2022-09-29T00:00:00+0100 +title: v1.4 Changelog +linkTitle: v1.4 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2022-09-29 --- - - -## v1.4 - - - - -
Git commithttps://github.com/matrix-org/matrix-spec/tree/v1.4
Release dateSeptember 29, 2022
- - -### Client-Server API +## Client-Server API Removed Endpoints @@ -58,7 +50,7 @@ Variables: - Clarify enum values by separating possible values with commas. ([#1240](https://github.com/matrix-org/matrix-spec/issues/1240)) -### Server-Server API +## Server-Server API Backwards Compatible Changes @@ -75,7 +67,7 @@ Variables: - Update "API Standards" section to clarify how JSON is used. ([#1185](https://github.com/matrix-org/matrix-spec/issues/1185)) -### Application Service API +## Application Service API Breaking Changes @@ -90,7 +82,7 @@ Variables: - Add HTML anchors for object definitions in the formatted specification. ([#1174](https://github.com/matrix-org/matrix-spec/issues/1174)) -### Identity Service API +## Identity Service API Spec Clarifications @@ -100,7 +92,7 @@ Variables: - Update "API Standards" section to clarify how JSON is used. ([#1185](https://github.com/matrix-org/matrix-spec/issues/1185)) -### Push Gateway API +## Push Gateway API Spec Clarifications @@ -109,7 +101,7 @@ Variables: - Add HTML anchors for object definitions in the formatted specification. ([#1174](https://github.com/matrix-org/matrix-spec/issues/1174)) -### Room Versions +## Room Versions Spec Clarifications @@ -120,13 +112,13 @@ Variables: - For room versions 7 through 10: Clarify that `invite->knock` is actually a legal transition. ([#1175](https://github.com/matrix-org/matrix-spec/issues/1175)) -### Appendices +## Appendices No significant changes. -### Internal Changes/Tooling +## Internal Changes/Tooling Backwards Compatible Changes diff --git a/content/changelog/v1.5.md b/content/changelog/v1.5.md index 258aabfa..71931cc7 100644 --- a/content/changelog/v1.5.md +++ b/content/changelog/v1.5.md @@ -1,23 +1,15 @@ --- -date: 2022-11-17T08:22:11-07:00 +title: v1.5 Changelog +linkTitle: v1.5 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2022-11-17 --- - - -## v1.5 - - - - -
Git commithttps://github.com/matrix-org/matrix-spec/tree/v1.5
Release dateNovember 17, 2022
- - -### Client-Server API +## Client-Server API Backwards Compatible Changes @@ -45,7 +37,7 @@ Variables: - Add example read receipt to `GET /_matrix/client/v3/sync` response example. ([#1341](https://github.com/matrix-org/matrix-spec/issues/1341)) -### Server-Server API +## Server-Server API Spec Clarifications @@ -54,7 +46,7 @@ Variables: - Fix a number of broken links in the specification. ([#1330](https://github.com/matrix-org/matrix-spec/issues/1330)) -### Application Service API +## Application Service API Spec Clarifications @@ -63,7 +55,7 @@ Variables: - Clarify that application services can only register an interest in local users, as per [MSC3905](https://github.com/matrix-org/matrix-spec-proposals/issues/3905). ([#1305](https://github.com/matrix-org/matrix-spec/issues/1305)) -### Identity Service API +## Identity Service API Spec Clarifications @@ -72,13 +64,13 @@ Variables: - Fix a number of broken links in the specification. ([#1330](https://github.com/matrix-org/matrix-spec/issues/1330)) -### Push Gateway API +## Push Gateway API No significant changes. -### Room Versions +## Room Versions Spec Clarifications @@ -89,13 +81,13 @@ No significant changes. - Fix a number of broken links in the specification. ([#1330](https://github.com/matrix-org/matrix-spec/issues/1330)) -### Appendices +## Appendices No significant changes. -### Internal Changes/Tooling +## Internal Changes/Tooling Backwards Compatible Changes diff --git a/content/changelog/v1.6.md b/content/changelog/v1.6.md index 07574ff3..f2a129c6 100644 --- a/content/changelog/v1.6.md +++ b/content/changelog/v1.6.md @@ -1,23 +1,15 @@ --- -date: 2023-02-14T08:25:40-07:00 +title: v1.6 Changelog +linkTitle: v1.6 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2023-02-14 --- - - -## v1.6 - - - - -
Git commithttps://github.com/matrix-org/matrix-spec/tree/v1.6
Release dateFebruary 14, 2023
- - -### Client-Server API +## Client-Server API Backwards Compatible Changes @@ -45,7 +37,7 @@ Variables: - Improve distinction between tags and their attributes in the rich text section. Contributed by Nico. ([#1433](https://github.com/matrix-org/matrix-spec/issues/1433)) -### Server-Server API +## Server-Server API Breaking Changes @@ -73,7 +65,7 @@ Variables: - Fix `edu_type` in EDU examples. ([#1383](https://github.com/matrix-org/matrix-spec/issues/1383)) -### Application Service API +## Application Service API Backwards Compatible Changes @@ -82,7 +74,7 @@ Variables: - Add information on standard error responses for unknown endpoints/methods, as per [MSC3743](https://github.com/matrix-org/matrix-spec-proposals/pull/3743). ([#1347](https://github.com/matrix-org/matrix-spec/issues/1347)) -### Identity Service API +## Identity Service API Backwards Compatible Changes @@ -91,7 +83,7 @@ Variables: - Add information on standard error responses for unknown endpoints/methods, as per [MSC3743](https://github.com/matrix-org/matrix-spec-proposals/pull/3743). ([#1347](https://github.com/matrix-org/matrix-spec/issues/1347)) -### Push Gateway API +## Push Gateway API Backwards Compatible Changes @@ -100,7 +92,7 @@ Variables: - Add information on standard error responses for unknown endpoints/methods, as per [MSC3743](https://github.com/matrix-org/matrix-spec-proposals/pull/3743). ([#1347](https://github.com/matrix-org/matrix-spec/issues/1347)) -### Room Versions +## Room Versions Backwards Compatible Changes @@ -116,13 +108,13 @@ Variables: - Fix various typos throughout the specification. ([#1423](https://github.com/matrix-org/matrix-spec/issues/1423)) -### Appendices +## Appendices No significant changes. -### Internal Changes/Tooling +## Internal Changes/Tooling Spec Clarifications diff --git a/content/changelog/v1.7.md b/content/changelog/v1.7.md index 61ade090..86f0b4ad 100644 --- a/content/changelog/v1.7.md +++ b/content/changelog/v1.7.md @@ -1,23 +1,15 @@ --- -date: 2023-05-25T09:47:21-06:00 +title: v1.7 Changelog +linkTitle: v1.7 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2023-05-25 --- - - -## v1.7 - - - - -
Git commithttps://github.com/matrix-org/matrix-spec/tree/v1.7
Release dateMay 25, 2023
- - -### Client-Server API +## Client-Server API New Endpoints @@ -63,7 +55,7 @@ Variables: - Add missing `knock_restricted` join rule to the `m.room.join_rules` schema. ([#1535](https://github.com/matrix-org/matrix-spec/issues/1535)) -### Server-Server API +## Server-Server API Spec Clarifications @@ -75,7 +67,7 @@ Variables: - Remove extraneous `age_ts` field from the reference hash calculation section. ([#1536](https://github.com/matrix-org/matrix-spec/issues/1536)) -### Application Service API +## Application Service API New Endpoints @@ -97,7 +89,7 @@ Variables: - Fix various typos throughout the specification. ([#1447](https://github.com/matrix-org/matrix-spec/issues/1447)) -### Identity Service API +## Identity Service API Spec Clarifications @@ -106,13 +98,13 @@ Variables: - Corrections to the response format of `/_matrix/identity/v2/store-invite`. ([#1486](https://github.com/matrix-org/matrix-spec/issues/1486)) -### Push Gateway API +## Push Gateway API No significant changes. -### Room Versions +## Room Versions Spec Clarifications @@ -121,7 +113,7 @@ No significant changes. - Clarifications of event ID formats in early room versions ([#1484](https://github.com/matrix-org/matrix-spec/issues/1484)) -### Appendices +## Appendices Spec Clarifications @@ -132,7 +124,7 @@ No significant changes. - Clarifications of event ID formats in early room versions. ([#1484](https://github.com/matrix-org/matrix-spec/issues/1484)) -### Internal Changes/Tooling +## Internal Changes/Tooling Spec Clarifications diff --git a/content/changelog/v1.8.md b/content/changelog/v1.8.md new file mode 100644 index 00000000..6e5cf995 --- /dev/null +++ b/content/changelog/v1.8.md @@ -0,0 +1,113 @@ +--- +title: v1.8 Changelog +linkTitle: v1.8 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2023-08-23 +--- + +## 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)) diff --git a/content/changelog/v1.9.md b/content/changelog/v1.9.md new file mode 100644 index 00000000..9c38785d --- /dev/null +++ b/content/changelog/v1.9.md @@ -0,0 +1,84 @@ +--- +title: v1.9 Changelog +linkTitle: v1.9 +type: docs +layout: changelog +outputs: + - html + - checklist +date: 2023-11-29 +--- + +## 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)) diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index 0e7e8473..bdee69b2 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -22,17 +22,23 @@ recommended outside test environments. Clients are authenticated using opaque `access_token` strings (see [Client Authentication](#client-authentication) for details). -All `POST` and `PUT` endpoints, with the exception of [`POST -/_matrix/media/v3/upload`](#post_matrixmediav3upload) and [`PUT -/_matrix/media/v3/upload/{serverName}/{mediaId}`](#put_matrixmediav3uploadservernamemediaid), +All `POST` and `PUT` endpoints, with the exception of those listed below, require the client to supply a request body containing a (potentially empty) JSON object. Clients should supply a `Content-Type` header of `application/json` for all requests with JSON bodies, but this is not required. +The exceptions are: + +- [`POST /_matrix/media/v3/upload`](#post_matrixmediav3upload) and + [`PUT /_matrix/media/v3/upload/{serverName}/{mediaId}`](#put_matrixmediav3uploadservernamemediaid), + both of which take the uploaded media as the request body. +- [`POST /_matrix/client/v3/logout`](#post_matrixclientv3logout) and + [`POST /_matrix/client/v3/logout/all`](#post_matrixclientv3logoutall), + which take an empty request body. + Similarly, all endpoints require the server to return a JSON object, -with the exception of 200 responses to -[`GET /_matrix/media/v3/download/{serverName}/{mediaId}`](#get_matrixmediav3downloadservernamemediaid) -and [`GET /_matrix/media/v3/thumbnail/{serverName}/{mediaId}`](#get_matrixmediav3thumbnailservernamemediaid). +with the exception of 200 responses to the media download endpoints in the +[Content Repository module](#content-repository). Servers must include a `Content-Type` header of `application/json` for all JSON responses. All JSON data, in requests or responses, must be encoded using UTF-8. @@ -94,6 +100,13 @@ section](#soft-logout) for more information. `M_MISSING_TOKEN` No access token was specified for the request. +`M_USER_LOCKED` +The account has been [locked](#account-locking) and cannot be used at this time. + +`M_USER_SUSPENDED` +The account has been [suspended](#account-suspension) and can only be used for +limited actions at this time. + `M_BAD_JSON` Request contained valid JSON, but it was malformed in some way, e.g. missing required keys, invalid values for keys. @@ -106,7 +119,7 @@ No resource was found for this request. `M_LIMIT_EXCEEDED` Too many requests have been sent in a short period of time. Wait a while -then try again. +then try again. See [Rate limiting](#rate-limiting). `M_UNRECOGNIZED` The server did not understand the request. This is expected to be returned with @@ -127,7 +140,7 @@ The request was not correctly authorized. Usually due to login failures. `M_USER_DEACTIVATED` The user ID associated with the request has been deactivated. Typically -for endpoints that prove authentication, such as `/login`. +for endpoints that prove authentication, such as [`/login`](#get_matrixclientv3login). `M_USER_IN_USE` Encountered when trying to register a user ID which has been taken. @@ -206,12 +219,43 @@ much memory or disk space. The error MUST have an `admin_contact` field to provide the user receiving the error a place to reach out to. Typically, this error will appear on routes which attempt to modify state (e.g.: sending messages, account data, etc) and not routes which -only read state (e.g.: `/sync`, get account data, etc). +only read state (e.g.: [`/sync`](#get_matrixclientv3sync), +[`/user/{userId}/account_data/{type}`](#get_matrixclientv3useruseridaccount_datatype), etc). `M_CANNOT_LEAVE_SERVER_NOTICE_ROOM` The user is unable to reject an invite to join the server notices room. See the [Server Notices](#server-notices) module for more information. +`M_THREEPID_MEDIUM_NOT_SUPPORTED` +The homeserver does not support adding a third party identifier of the given medium. + +`M_THREEPID_IN_USE` +The third party identifier specified by the client is not acceptable because it is +already in use in some way. + +#### Rate limiting + +Homeservers SHOULD implement rate limiting to reduce the risk of being +overloaded. If a request is refused due to rate limiting, it should +return a standard error response of the form: + +```json +{ + "errcode": "M_LIMIT_EXCEEDED", + "error": "string", + "retry_after_ms": integer (optional, deprecated) +} +``` + +Homeservers SHOULD include a [`Retry-After`](https://www.rfc-editor.org/rfc/rfc9110#field.retry-after) +header for any response with a 429 status code. + +The `retry_after_ms` property MAY be included to tell the client how long +they have to wait in milliseconds before they can try again. This property is +deprecated, in favour of the `Retry-After` header. + +{{% changed-in v="1.10" %}}: `retry_after_ms` property deprecated in favour of `Retry-After` header. + ### Transaction identifiers The client-server API typically uses `HTTP PUT` to submit requests with @@ -223,9 +267,10 @@ the request idempotent. The transaction ID should **only** be used for this purpose. -From the client perspective, after the request has finished, the `{txnId}` -value should be changed by for the next request (how is not specified; a -monotonically increasing integer is recommended). +After the request has finished, clients should change the `{txnId}` value for +the next request. How this is achieved, is left as an implementation detail. +It is recommended that clients use either version 4 UUIDs or a concatenation +of the current timestamp and a monotonically increasing integer. The homeserver should identify a request as a retransmission if the transaction ID is the same as a previous request, and the path of the @@ -233,7 +278,7 @@ HTTP request is the same. Where a retransmission has been identified, the homeserver should return the same HTTP response code and content as the original request. -For example, `PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}` +For example, [`PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}`](#put_matrixclientv3roomsroomidsendeventtypetxnid) would return a `200 OK` with the `event_id` of the original request in the response body. @@ -284,6 +329,15 @@ headers to be returned by servers on all requests are: Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-Headers: X-Requested-With, Content-Type, Authorization +{{% boxes/note %}} +{{% added-in v="1.13" %}} The recommended value of the `Access-Control-Allow-Methods` +header only covers the existing endpoints in the specification. Servers which +support additional endpoints or methods should add those methods as well. + +This section will be updated whenever a new method is supported by an endpoint. +Examples of possible future-use methods include `PATCH` and `HEAD`. +{{% /boxes/note %}} + ## Server Discovery In order to allow users to connect to a Matrix server without needing to @@ -327,9 +381,9 @@ as per the [CORS](#web-browser-clients) section in this specification. The `.well-known` method uses a JSON file at a predetermined location to specify parameter values. The flow for this method is as follows: -1. Extract the server name from the user's Matrix ID by splitting the +1. Extract the [server name](/appendices/#server-name) from the user's Matrix ID by splitting the Matrix ID at the first colon. -2. Extract the hostname from the server name. +2. Extract the hostname from the server name as described by the [grammar](/appendices/#server-name). 3. Make a GET request to `https://hostname/.well-known/matrix/client`. 1. If the returned status code is 404, then `IGNORE`. 2. If the returned status code is not 200, or the response body is @@ -363,11 +417,12 @@ specify parameter values. The flow for this method is as follows: {{% http-api spec="client-server" api="versions" %}} +{{% http-api spec="client-server" api="support" %}} + ## Client Authentication Most API endpoints require the user to identify themselves by presenting -previously obtained credentials in the form of an `access_token` query -parameter or through an Authorization Header of `Bearer $access_token`. +previously obtained credentials in the form of an access token. An access token is typically obtained via the [Login](#login) or [Registration](#account-registration-and-management) processes. Access tokens can expire; a new access token can be generated by using a refresh token. @@ -381,16 +436,19 @@ investigate [macaroons](http://research.google.com/pubs/pub41892.html). ### Using access tokens -Access tokens may be provided in two ways, both of which the homeserver -MUST support: +Access tokens may be provided via a request header, using the Authentication +Bearer scheme: `Authorization: Bearer TheTokenHere`. -1. Via a query string parameter, `access_token=TheTokenHere`. -2. Via a request header, `Authorization: Bearer TheTokenHere`. +Clients may alternatively provide the access token via a query string parameter: +`access_token=TheTokenHere`. This method is deprecated to prevent the access +token being leaked in access/HTTP logs and SHOULD NOT be used by clients. -Clients are encouraged to use the `Authorization` header where possible -to prevent the access token being leaked in access/HTTP logs. The query -string should only be used in cases where the `Authorization` header is -inaccessible for the client. +Homeservers MUST support both methods. + +{{% boxes/note %}} +{{% changed-in v="1.11" %}} +Sending the access token as a query string parameter is now deprecated. +{{% /boxes/note %}} When credentials are required but missing or invalid, the HTTP call will return with a status of 401 and the error code, `M_MISSING_TOKEN` or @@ -400,7 +458,7 @@ could mean one of four things: 1. the access token was never valid. 2. the access token has been logged out. 3. the access token has been [soft logged out](#soft-logout). -4. {{< added-in v="1.3" >}} the access token [needs to be refreshed](#refreshing-access-tokens). +4. {{% added-in v="1.3" %}} the access token [needs to be refreshed](#refreshing-access-tokens). When a client receives an error code of `M_UNKNOWN_TOKEN`, it should: @@ -483,6 +541,10 @@ token available. If it does not have a refresh token available, or refreshing fails with `soft_logout: true`, the client can acquire a new access token by specifying the device ID it is already using to the login API. +{{% changed-in v="1.12" %}} A client that receives such a response together +with an `M_USER_LOCKED` error code, cannot obtain a new access token until +the account has been [unlocked](#account-locking). + ### User-Interactive Authentication API #### Overview @@ -520,8 +582,10 @@ request parameter. A client should first make a request with no `auth` parameter. The homeserver returns an HTTP 401 response, with a JSON body, as follows: - HTTP/1.1 401 Unauthorized - Content-Type: application/json +``` +HTTP/1.1 401 Unauthorized +Content-Type: application/json +``` ```json { @@ -564,8 +628,10 @@ given. It also contains other keys dependent on the auth type being attempted. For example, if the client is attempting to complete auth type `example.type.foo`, it might submit something like this: - POST /_matrix/client/v3/endpoint HTTP/1.1 - Content-Type: application/json +``` +POST /_matrix/client/v3/endpoint HTTP/1.1 +Content-Type: application/json +``` ```json { @@ -585,8 +651,10 @@ along with the same object as when no authentication was attempted, with the addition of the `completed` key which is an array of auth types the client has completed successfully: - HTTP/1.1 401 Unauthorized - Content-Type: application/json +``` +HTTP/1.1 401 Unauthorized +Content-Type: application/json +``` ```json { @@ -617,8 +685,10 @@ but the client may make a second attempt, it returns the same HTTP status 401 response as above, with the addition of the standard `errcode` and `error` fields describing the error. For example: - HTTP/1.1 401 Unauthorized - Content-Type: application/json +``` +HTTP/1.1 401 Unauthorized +Content-Type: application/json +``` ```json { @@ -645,8 +715,10 @@ status 401 response as above, with the addition of the standard If the request fails for a reason other than authentication, the server returns an error message in the standard format. For example: - HTTP/1.1 400 Bad request - Content-Type: application/json +``` +HTTP/1.1 400 Bad request +Content-Type: application/json +``` ```json { @@ -843,7 +915,7 @@ follows: ``` Note that `id_server` (and therefore `id_access_token`) is optional if -the `/requestToken` request did not include them. +the [`/requestToken`](#post_matrixclientv3registeremailrequesttoken) request did not include them. ##### Phone number/MSISDN-based (identity / homeserver) @@ -872,7 +944,7 @@ follows: ``` Note that `id_server` (and therefore `id_access_token`) is optional if -the `/requestToken` request did not include them. +the [`/requestToken`](#post_matrixclientv3registermsisdnrequesttoken) request did not include them. ##### Dummy Auth @@ -919,11 +991,12 @@ or completely closed registration (where the homeserver administrators create and distribute accounts). The token required for this authentication type is shared out of band from -Matrix and is an opaque string with maximum length of 64 characters in the -range `[A-Za-z0-9._~-]`. The server can keep any number of tokens for any -length of time/validity. Such cases might be a token limited to 100 uses or -for the next 2 hours - after the tokens expire, they can no longer be used -to create accounts. +Matrix and is an opaque string using the [Opaque Identifier +Grammar](/appendices#opaque-identifiers), with maximum length of 64 +characters. The server can keep any number of tokens for any length of +time/validity. Such cases might be a token limited to 100 uses or for the next +2 hours - after the tokens expire, they can no longer be used to create +accounts. To use this authentication type, clients should submit an auth dict with just the type, token, and session: @@ -943,6 +1016,129 @@ in the registration process that their token has expired. {{% http-api spec="client-server" api="registration_tokens" %}} +##### Terms of service at registration + +{{% added-in v="1.11" %}} + +| Type | Description | +|--------------------------|--------------------------------------------------------------------------| +| `m.login.terms` | Authentication requires the user to accept a set of policy documents. | + +{{% boxes/note %}} +The `m.login.terms` authentication type is only valid on the +[`/register`](#post_matrixclientv3register) endpoint. +{{% /boxes/note %}} + +This authentication type is used when the homeserver requires new users to +accept a given set of policy documents, such as a terms of service and a privacy +policy. There may be many different types of documents, all of which are +versioned and presented in (potentially) multiple languages. + +When the server requires the user to accept some terms, it does so by returning +a 401 response to the `/register` request, where the response body includes +`m.login.terms` in the `flows` list, and the `m.login.terms` property in the +`params` object has the structure [shown below](#definition-mloginterms-params). + +If a client encounters an invalid parameter, registration should stop with an +error presented to the user. + +The client should present the user with a checkbox to accept each policy, +including a link to the provided URL. Once the user has done so, the client +submits an `auth` dict with just the `type` and `session`, as follows, to +indicate that all of the policies have been accepted: + +```json +{ + "type": "m.login.terms", + "session": "" +} +``` + +The server is expected to track which document versions it presented to the +user during registration, if applicable. + + +**Example** + +1. A client might submit a registration request as follows: + + ``` + POST /_matrix/client/v3/register + ``` + ```json + { + "username": "cheeky_monkey", + "password": "ilovebananas" + } + ``` + +2. The server requires the user to accept some terms of service before + registration, so returns the following response: + + ``` + HTTP/1.1 401 Unauthorized + Content-Type: application/json + ``` + ```json + { + "flows": [ + { "stages": [ "m.login.terms" ] } + ], + "params": { + "m.login.terms": { + "policies": { + "terms_of_service": { + "version": "1.2", + "en": { + "name": "Terms of Service", + "url": "https://example.org/somewhere/terms-1.2-en.html" + }, + "fr": { + "name": "Conditions d'utilisation", + "url": "https://example.org/somewhere/terms-1.2-fr.html" + } + } + } + } + }, + "session": "kasgjaelkgj" + } + ``` + +3. The client presents the list of documents to the user, inviting them to + accept the polices. + +4. The client repeats the registration request, confirming that the user has + accepted the documents: + ``` + POST /_matrix/client/v3/register + ``` + ```json + { + "username": "cheeky_monkey", + "password": "ilovebananas", + "auth": { + "type": "m.login.terms", + "session": "kasgjaelkgj" + } + } + ``` + +5. All authentication steps have now completed, so the request is successful: + ``` + HTTP/1.1 200 OK + Content-Type: application/json + ``` + ```json + { + "access_token": "abc123", + "device_id": "GHTYAJCE", + "user_id": "@cheeky_monkey:matrix.org" + } + ``` + +{{% definition path="api/client-server/definitions/m.login.terms_params" %}} + #### Fallback Clients cannot be expected to be able to know how to process every @@ -1118,7 +1314,7 @@ from. ### Login -A client can obtain access tokens using the `/login` API. +A client can obtain access tokens using the [`/login`](#post_matrixclientv3login) API. Note that this endpoint does not currently use the [User-Interactive Authentication @@ -1176,8 +1372,8 @@ client supports it, the client should redirect the user to the is complete, the client will need to submit a `/login` request matching `m.login.token`. -{{< added-in v="1.7" >}} Already-authenticated clients can additionally generate -a token for their user ID if supported by the homeserver using +{{% added-in v="1.7" %}} Already-authenticated clients can additionally generate +a token for their user ID if supported by the homeserver using [`POST /login/get_token`](/client-server-api/#post_matrixclientv1loginget_token). {{% http-api spec="client-server" api="login" %}} @@ -1234,7 +1430,10 @@ fallback login API: This returns an HTML and JavaScript page which can perform the entire login process. The page will attempt to call the JavaScript function -`window.onLogin` when login has been successfully completed. +`window.matrixLogin.onLogin(response)` when login has been successfully +completed. The argument, `response`, is the JSON response body of +[`POST /_matrix/client/v3/login`](#post_matrixclientv3login) parsed +into a JavaScript object. {{% added-in v="1.1" %}} Non-credential parameters valid for the `/login` endpoint can be provided as query string parameters here. These are to be @@ -1255,6 +1454,122 @@ number and a symbol and be at a minimum 8 characters in length. Servers MAY reject weak passwords with an error code `M_WEAK_PASSWORD`. {{% /boxes/warning %}} +#### Account locking + +{{% added-in v="1.12" %}} + +Server administrators may apply locks to prevent users from usefully +using their accounts, for instance, due to safety or security concerns. +In contrast to account deactivation, locking is a non-destructive action +that can be reversed. This specification describes the behaviour of clients +and servers when an account is locked. It deliberately leaves the methods +for locking and unlocking accounts as a server implementation detail. + +When an account is locked, servers MUST return a `401 Unauthorized` error +response with an `M_USER_LOCKED` error code and [`soft_logout`](#soft-logout) +set to `true` on all but the following Client-Server APIs: + +- [`POST /logout`](#post_matrixclientv3logout) +- [`POST /logout/all`](#post_matrixclientv3logoutall) + +Servers MAY additionally include details of why the lock was applied in +the `error` field. + +``` +HTTP/1.1 401 Unauthorized +Content-Type: application/json +``` + +```json +{ + "errcode": "M_USER_LOCKED", + "error": "This account has been locked", + "soft_logout": true +} +``` + +Servers SHOULD NOT invalidate access tokens on locked accounts unless the +client requests a logout (using the above endpoints). This ensures that +users can retain their sessions without having to log back in if the account +becomes unlocked. + +Upon receiving an `M_USER_LOCKED` error, clients SHOULD retain session +information including encryption state and inform the user that their account +has been locked. While the lock is applied, clients SHOULD hide the normal UI +from the user, preventing general use of their account. Clients SHOULD, however, +continue to make rate-limited requests to [`/sync`](#get_matrixclientv3sync) +and other APIs to detect when the lock has been lifted. + +To enable users to appeal to a lock clients MAY use +[server contact discovery](#getwell-knownmatrixsupport). + +#### Account suspension + +{{% added-in v="1.13" %}} + +Server administrators MAY suspend a user's account to prevent further activity +from that account. The effect is similar to [locking](#account-locking), though +without risk of the client losing state from a logout. Suspensions are reversible, +like locks and unlike deactivations. + +The actions a user can perform while suspended is deliberately left as an +implementation detail. Servers SHOULD permit the user to perform at least the +following, however: + +* Log in and create additional sessions (which are also suspended). +* See and receive messages, particularly through [`/sync`](#get_matrixclientv3sync) + and [`/messages`](#get_matrixclientv3roomsroomidmessages). +* [Verify other devices](#device-verification) and write associated + [cross-signing data](#cross-signing). +* [Populate their key backup](#server-side-key-backups). +* [Leave rooms and reject invites](#post_matrixclientv3roomsroomidleave). +* [Redact](#redactions) their own events. +* [Log out](#post_matrixclientv3logout) or [delete](#delete_matrixclientv3devicesdeviceid) + any device of theirs, including the current session. +* [Deactivate](#post_matrixclientv3accountdeactivate) their account, potentially + with a time delay to discourage making a new account right away. +* Change or add [admin contacts](#adding-account-administrative-contact-information), + but not remove. Servers are recommended to only permit this if they keep a + changelog on contact information to prevent misuse. + +General purpose endpoints like [`/send/{eventType}`](#put_matrixclientv3roomsroomidsendeventtypetxnid) +MAY return the error described below depending on the path parameters. For example, +a user may be allowed to send `m.room.redaction` events but not `m.room.message` +events through `/send`. + +Where a room is used to maintain communication between server administration +teams and the suspended user, servers are recommended to allow the user to send +events to that room specifically. Server administrators which do not want the +user to continue receiving messages may be interested in [account locking](#account-locking) +instead. + +Otherwise, the recommended set of explicitly forbidden actions is: + +* [Joining](#joining-rooms) or [knocking](#knocking-on-rooms) on rooms. +* Accepting or sending [invites](#room-membership). +* [Sending messages](#put_matrixclientv3roomsroomidsendeventtypetxnid) to rooms. +* Changing [profile data](#profiles) (display name and avatar, primarily). +* [Redacting](#redactions) other users' events, when permission is possible in a room. + +When a client attempts to perform an action while suspended, the server MUST +respond with a `403 Forbidden` error response with `M_USER_SUSPENDED` as the +error code, as shown below: + +``` +HTTP/1.1 403 Forbidden +Content-Type: application/json +``` + +```json +{ + "errcode": "M_USER_SUSPENDED", + "error": "You cannot perform this action while suspended." +} +``` + +APIs for initiating suspension or unsuspension are not included in this version +of the specification, and left as an implementation detail. + ### Adding Account Administrative Contact Information A homeserver may keep some contact information for administrative use. @@ -1324,7 +1639,7 @@ The capabilities advertised through this system are intended to advertise functionality which is optional in the API, or which depend in some way on the state of the user or server. This system should not be used to advertise unstable or experimental features - this is better -done by the `/versions` endpoint. +done by the [`/versions`](#get_matrixclientversions) endpoint. Some examples of what a reasonable capability could be are: @@ -1353,7 +1668,7 @@ specification are defined later in this section. ### `m.change_password` capability This capability has a single flag, `enabled`, which indicates whether or -not the user can use the `/account/password` API to change their +not the user can use the [`/account/password`](#post_matrixclientv3accountpassword) API to change their password. If not present, the client should assume that password changes are possible via the API. When present, clients SHOULD respect the capability's `enabled` flag and indicate to the user if they are unable @@ -1484,6 +1799,27 @@ An example of the capability API's response for this capability is: } ``` +### `m.get_login_token` capability + +This capability has a single flag, `enabled`, to denote whether the user +is able to use [`POST /login/get_token`](/client-server-api/#post_matrixclientv1loginget_token) +to generate single-use, time-limited tokens to log unauthenticated clients +into their account. + +When not listed, clients SHOULD assume the user is unable to generate tokens. + +An example of the capability API's response for this capability is: + +```json +{ + "capabilities": { + "m.get_login_token": { + "enabled": false + } + } +} +``` + ## Filtering Filters can be created on the server and can be passed as a parameter to @@ -1505,24 +1841,26 @@ events to the client to ease implementation, although such redundancy should be minimised where possible to conserve bandwidth. In terms of filters, lazy-loading is enabled by enabling -`lazy_load_members` on a `RoomEventFilter` (or a `StateFilter` in the -case of `/sync` only). When enabled, lazy-loading aware endpoints (see +`lazy_load_members` on a +[`RoomEventFilter`](#post_matrixclientv3useruseridfilter_request_roomeventfilter). +When enabled, lazy-loading aware endpoints (see below) will only include membership events for the `sender` of events being included in the response. For example, if a client makes a `/sync` request with lazy-loading enabled, the server will only return membership events for the `sender` of events in the timeline, not all members of a room. -When processing a sequence of events (e.g. by looping on `/sync` or -paginating `/messages`), it is common for blocks of events in the -sequence to share a similar set of senders. Rather than responses in the -sequence sending duplicate membership events for these senders to the -client, the server MAY assume that clients will remember membership -events they have already been sent, and choose to skip sending -membership events for members whose membership has not changed. These -are called 'redundant membership events'. Clients may request that -redundant membership events are always included in responses by setting -`include_redundant_members` to true in the filter. +When processing a sequence of events (e.g. by looping on +[`/sync`](#get_matrixclientv3sync) or paginating +[`/messages`](#get_matrixclientv3roomsroomidmessages)), it is common for blocks +of events in the sequence to share a similar set of senders. Rather than +responses in the sequence sending duplicate membership events for these senders +to the client, the server MAY assume that clients will remember membership +events they have already been sent, and choose to skip sending membership +events for members whose membership has not changed. These are called +'redundant membership events'. Clients may request that redundant membership +events are always included in responses by setting `include_redundant_members` +to true in the filter. The expected pattern for using lazy-loading is currently: @@ -1537,7 +1875,7 @@ The expected pattern for using lazy-loading is currently: incremental /sync responses. - Clients which do not support tab-completion may instead pull in profiles for arbitrary users (e.g. read receipts, typing - notifications) on demand by querying the room state or `/profile`. + notifications) on demand by querying the room state or [`/profile`](#get_matrixclientv3profileuserid). The current endpoints which support lazy-loading room members are: @@ -1682,16 +2020,15 @@ updates not being sent. The complete event MUST NOT be larger than 65536 bytes, when formatted with the [federation event format](#room-event-format), including any -signatures, and encoded as [Canonical -JSON](/appendices#canonical-json). +signatures, and encoded as [Canonical JSON](/appendices#canonical-json). There are additional restrictions on sizes per key: -- `sender` MUST NOT exceed 255 bytes (including domain). -- `room_id` MUST NOT exceed 255 bytes. +- `sender` MUST NOT exceed the size limit for [user IDs](/appendices/#user-identifiers). +- `room_id` MUST NOT exceed the size limit for [room IDs](/appendices/#room-ids). - `state_key` MUST NOT exceed 255 bytes. - `type` MUST NOT exceed 255 bytes. -- `event_id` MUST NOT exceed 255 bytes. +- `event_id` MUST NOT exceed the size limit for [event IDs](/appendices/#event-ids). Some event types have additional size restrictions which are specified in the description of the event. Additional keys have no limit other @@ -2096,11 +2433,11 @@ The endpoints where the server *should* include bundled aggregations are: * [`GET /sync`](#get_matrixclientv3sync) when the relevant section has a `limited` value of `true`. * [`POST /search`](#post_matrixclientv3search) for any matching events under `room_events`. -* {{< added-in v="1.4" >}} [`GET /rooms/{roomId}/threads`](#get_matrixclientv1roomsroomidthreads) +* {{% added-in v="1.4" %}} [`GET /rooms/{roomId}/threads`](#get_matrixclientv1roomsroomidthreads) {{% boxes/note %}} The server is **not** required to return bundled aggregations on deprecated endpoints -such as `/initialSync`. +such as [`/initialSync`](#get_matrixclientv3roomsroomidinitialsync). {{% /boxes/note %}} While this functionality allows the client to see what was known to the server at the @@ -2156,6 +2493,19 @@ following endpoint. This endpoint is particularly useful if the client has lost context on the aggregation for a parent event and needs to rebuild/verify it. +When using the `recurse` parameter, note that there is no way for a client to +control how far the server recurses. If the client decides that the server's +recursion level is insufficient, it could, for example, perform the recursion +itself, or disable whatever feature requires more recursion. + +Filters specified via `event_type` or `rel_type` will be applied to all events +returned, whether direct or indirect relations. Events that would match the filter, +but whose only relation to the original given event is through a non-matching +intermediate event, will not be included. This means that supplying a `rel_type` +parameter of `m.thread` is not appropriate for fetching all events in a thread since +relations to the threaded events would be filtered out. For this purpose, clients should +omit the `rel_type` parameter and perform any necessary filtering on the client side. + {{% boxes/note %}} Because replies do not use `rel_type`, they will not be accessible via this API. {{% /boxes/note %}} @@ -2309,7 +2659,7 @@ Note that this rule is only expected to work in room versions The allowable state transitions of membership are: -![membership-flow-diagram](/diagrams/membership.png) +{{% diagram name="membership" alt="Diagram presenting the possible membership state transitions" %}} {{% http-api spec="client-server" api="list_joined_rooms" %}} @@ -2340,9 +2690,10 @@ this will have been just the API definition and nothing more (like invites). If the join rules allow, external users to the room can `/knock` on it to request permission to join. Users with appropriate permissions within the -room can then approve (`/invite`) or deny (`/kick`, `/ban`, or otherwise +room can then approve ([`/invite`](#post_matrixclientv3roomsroomidinvite)) +or deny ([`/kick`](#post_matrixclientv3roomsroomidkick), [`/ban`](#post_matrixclientv3roomsroomidban), or otherwise set membership to `leave`) the knock. Knocks can be retracted by calling -`/leave` or otherwise setting membership to `leave`. +[`/leave`](#post_matrixclientv3roomsroomidleave) or otherwise setting membership to `leave`. Users who are currently in the room, already invited, or banned cannot knock on the room. @@ -2392,9 +2743,6 @@ join is happening over federation, the remote server will check the conditions before accepting the join. See the [Server-Server Spec](/server-server-api/#restricted-rooms) for more information. -If the room is `restricted` but no valid conditions are presented then the -room is effectively invite only. - The user does not need to maintain the conditions in order to stay a member of the room: the conditions are only checked/evaluated during the join process. @@ -2464,12 +2812,12 @@ with: "user_id": "", "reason": "string: " } -```` +``` Banning a user adjusts the banned member's membership state to `ban`. Like with other membership changes, a user can directly adjust the target member's state, by making a request to -`/rooms//state/m.room.member/`: +[`/rooms//state/m.room.member/`](#put_matrixclientv3roomsroomidstateeventtypestatekey): ```json { @@ -2497,7 +2845,25 @@ re-invited. {{% http-api spec="client-server" api="profile" %}} -#### Events on Change of Profile Information +#### Server behaviour + +Homeservers MUST at a minimum allow profile look-up for: + +- users that share a room with the requesting user +- users that reside in public rooms known to the homeserver + +In all other cases, homeservers MAY deny profile look-up by responding with +403 and an error code of `M_FORBIDDEN`. + +When a remote user is queried and the query is not denied per the above, +homeservers SHOULD query the remote server for the user's profile information. +The remote server MAY itself deny profile queries over federation, however. + +When the requested user does not exist, homeservers MAY choose whether to +respond with 403 or 404. If the server denies profile look-up in all but the +required cases, 403 is RECOMMENDED. + +##### Events on Change of Profile Information Because the profile display name and avatar information are likely to be used in many places of a client's display, changes to these fields cause @@ -2521,25 +2887,6 @@ users, they should include the display name and avatar URL fields in these events so that clients already have these details to hand, and do not have to perform extra round trips to query it. -## Security - -### Rate limiting - -Homeservers SHOULD implement rate limiting to reduce the risk of being -overloaded. If a request is refused due to rate limiting, it should -return a standard error response of the form: - -```json -{ - "errcode": "M_LIMIT_EXCEEDED", - "error": "string", - "retry_after_ms": integer (optional) -} -``` - -The `retry_after_ms` key SHOULD be included to tell the client how long -they have to wait in milliseconds before they can try again. - ## Modules Modules are parts of the Client-Server API which are not universal to @@ -2567,42 +2914,45 @@ that profile. | Module / Profile | Web | Mobile | Desktop | CLI | Embedded | |------------------------------------------------------------|-----------|----------|----------|----------|----------| -| [Instant Messaging](#instant-messaging) | Required | Required | Required | Required | Optional | -| [Rich replies](#rich-replies) | Optional | Optional | Optional | Optional | Optional | +| [Content Repository](#content-repository) | Required | Required | Required | Optional | Optional | | [Direct Messaging](#direct-messaging) | Required | Required | Required | Required | Optional | -| [Mentions](#user-and-room-mentions) | Required | Required | Required | Optional | Optional | +| [Ignoring Users](#ignoring-users) | Required | Required | Required | Optional | Optional | +| [Instant Messaging](#instant-messaging) | Required | Required | Required | Required | Optional | | [Presence](#presence) | Required | Required | Required | Required | Optional | | [Push Notifications](#push-notifications) | Optional | Required | Optional | Optional | Optional | | [Receipts](#receipts) | Required | Required | Required | Required | Optional | -| [Fully read markers](#fully-read-markers) | Optional | Optional | Optional | Optional | Optional | -| [Typing Notifications](#typing-notifications) | Required | Required | Required | Required | Optional | -| [VoIP](#voice-over-ip) | Required | Required | Required | Optional | Optional | -| [Ignoring Users](#ignoring-users) | Required | Required | Required | Optional | Optional | -| [Reporting Content](#reporting-content) | Optional | Optional | Optional | Optional | Optional | -| [Content Repository](#content-repository) | Required | Required | Required | Optional | Optional | -| [Managing History Visibility](#room-history-visibility) | Required | Required | Required | Required | Optional | -| [Server Side Search](#server-side-search) | Optional | Optional | Optional | Optional | Optional | +| [Room History Visibility](#room-history-visibility) | Required | Required | Required | Required | Optional | | [Room Upgrades](#room-upgrades) | Required | Required | Required | Required | Optional | -| [Server Administration](#server-administration) | Optional | Optional | Optional | Optional | Optional | -| [Event Context](#event-context) | Optional | Optional | Optional | Optional | Optional | -| [Third-party Networks](#third-party-networks) | Optional | Optional | Optional | Optional | Optional | -| [Send-to-Device Messaging](#send-to-device-messaging) | Optional | Optional | Optional | Optional | Optional | +| [Third-party Invites](#third-party-invites) | Optional | Required | Optional | Optional | Optional | +| [Typing Notifications](#typing-notifications) | Required | Required | Required | Required | Optional | +| [User and Room Mentions](#user-and-room-mentions) | Required | Required | Required | Optional | Optional | +| [Voice over IP](#voice-over-ip) | Required | Required | Required | Optional | Optional | +| [Client Config](#client-config) | Optional | Optional | Optional | Optional | Optional | | [Device Management](#device-management) | Optional | Optional | Optional | Optional | Optional | | [End-to-End Encryption](#end-to-end-encryption) | Optional | Optional | Optional | Optional | Optional | -| [Guest Accounts](#guest-access) | Optional | Optional | Optional | Optional | Optional | -| [Room Previews](#room-previews) | Optional | Optional | Optional | Optional | Optional | -| [Client Config](#client-config) | Optional | Optional | Optional | Optional | Optional | -| [SSO Login](#sso-client-loginauthentication) | Optional | Optional | Optional | Optional | Optional | -| [OpenID](#openid) | Optional | Optional | Optional | Optional | Optional | -| [Stickers](#sticker-messages) | Optional | Optional | Optional | Optional | Optional | -| [Server ACLs](#server-access-control-lists-acls-for-rooms) | Optional | Optional | Optional | Optional | Optional | -| [Server Notices](#server-notices) | Optional | Optional | Optional | Optional | Optional | -| [Moderation policies](#moderation-policy-lists) | Optional | Optional | Optional | Optional | Optional | -| [Spaces](#spaces) | Optional | Optional | Optional | Optional | Optional | -| [Event Replacements](#event-replacements) | Optional | Optional | Optional | Optional | Optional | | [Event Annotations and reactions](#event-annotations-and-reactions) | Optional | Optional | Optional | Optional | Optional | -| [Threading](#threading) | Optional | Optional | Optional | Optional | Optional | +| [Event Context](#event-context) | Optional | Optional | Optional | Optional | Optional | +| [Event Replacements](#event-replacements) | Optional | Optional | Optional | Optional | Optional | +| [Read and Unread Markers](#read-and-unread-markers) | Optional | Optional | Optional | Optional | Optional | +| [Guest Access](#guest-access) | Optional | Optional | Optional | Optional | Optional | +| [Moderation Policy Lists](#moderation-policy-lists) | Optional | Optional | Optional | Optional | Optional | +| [OpenID](#openid) | Optional | Optional | Optional | Optional | Optional | | [Reference Relations](#reference-relations) | Optional | Optional | Optional | Optional | Optional | +| [Reporting Content](#reporting-content) | Optional | Optional | Optional | Optional | Optional | +| [Rich replies](#rich-replies) | Optional | Optional | Optional | Optional | Optional | +| [Room Previews](#room-previews) | Optional | Optional | Optional | Optional | Optional | +| [Room Tagging](#room-tagging) | Optional | Optional | Optional | Optional | Optional | +| [SSO Client Login/Authentication](#sso-client-loginauthentication) | Optional | Optional | Optional | Optional | Optional | +| [Secrets](#secrets) | Optional | Optional | Optional | Optional | Optional | +| [Send-to-Device Messaging](#send-to-device-messaging) | Optional | Optional | Optional | Optional | Optional | +| [Server Access Control Lists (ACLs)](#server-access-control-lists-acls-for-rooms) | Optional | Optional | Optional | Optional | Optional | +| [Server Administration](#server-administration) | Optional | Optional | Optional | Optional | Optional | +| [Server Notices](#server-notices) | Optional | Optional | Optional | Optional | Optional | +| [Server Side Search](#server-side-search) | Optional | Optional | Optional | Optional | Optional | +| [Spaces](#spaces) | Optional | Optional | Optional | Optional | Optional | +| [Sticker Messages](#sticker-messages) | Optional | Optional | Optional | Optional | Optional | +| [Third-party Networks](#third-party-networks) | Optional | Optional | Optional | Optional | Optional | +| [Threading](#threading) | Optional | Optional | Optional | Optional | Optional | *Please see each module for more details on what clients need to implement.* @@ -2651,42 +3001,42 @@ operations and run in a resource constrained environment. Like embedded applications, they are not intended to be fully-fledged communication systems. -{{< cs-module name="instant_messaging" >}} -{{< cs-module name="rich_replies" >}} -{{< cs-module name="voip_events" >}} -{{< cs-module name="typing_notifications" >}} -{{< cs-module name="receipts" >}} -{{< cs-module name="read_markers" >}} -{{< cs-module name="presence" >}} -{{< cs-module name="content_repo" >}} -{{< cs-module name="send_to_device" >}} -{{< cs-module name="device_management" >}} -{{< cs-module name="end_to_end_encryption" >}} -{{< cs-module name="secrets" >}} -{{< cs-module name="history_visibility" >}} -{{< cs-module name="push" >}} -{{< cs-module name="third_party_invites" >}} -{{< cs-module name="search" >}} -{{< cs-module name="guest_access" >}} -{{< cs-module name="room_previews" >}} -{{< cs-module name="tags" >}} -{{< cs-module name="account_data" >}} -{{< cs-module name="admin" >}} -{{< cs-module name="event_context" >}} -{{< cs-module name="sso_login" >}} -{{< cs-module name="dm" >}} -{{< cs-module name="ignore_users" >}} -{{< cs-module name="stickers" >}} -{{< cs-module name="report_content" >}} -{{< cs-module name="third_party_networks" >}} -{{< cs-module name="openid" >}} -{{< cs-module name="server_acls" >}} -{{< cs-module name="mentions" >}} -{{< cs-module name="room_upgrades" >}} -{{< cs-module name="server_notices" >}} -{{< cs-module name="moderation_policies" >}} -{{< cs-module name="spaces" >}} -{{< cs-module name="event_replacements" >}} -{{< cs-module name="event_annotations" >}} -{{< cs-module name="threading" >}} -{{< cs-module name="reference_relations" >}} +{{% cs-module name="instant_messaging" %}} +{{% cs-module name="rich_replies" %}} +{{% cs-module name="voip_events" %}} +{{% cs-module name="typing_notifications" %}} +{{% cs-module name="receipts" %}} +{{% cs-module name="read_markers" %}} +{{% cs-module name="presence" %}} +{{% cs-module name="content_repo" %}} +{{% cs-module name="send_to_device" %}} +{{% cs-module name="device_management" %}} +{{% cs-module name="end_to_end_encryption" %}} +{{% cs-module name="secrets" %}} +{{% cs-module name="history_visibility" %}} +{{% cs-module name="push" %}} +{{% cs-module name="third_party_invites" %}} +{{% cs-module name="search" %}} +{{% cs-module name="guest_access" %}} +{{% cs-module name="room_previews" %}} +{{% cs-module name="tags" %}} +{{% cs-module name="account_data" %}} +{{% cs-module name="admin" %}} +{{% cs-module name="event_context" %}} +{{% cs-module name="sso_login" %}} +{{% cs-module name="dm" %}} +{{% cs-module name="ignore_users" %}} +{{% cs-module name="stickers" %}} +{{% cs-module name="report_content" %}} +{{% cs-module name="third_party_networks" %}} +{{% cs-module name="openid" %}} +{{% cs-module name="server_acls" %}} +{{% cs-module name="mentions" %}} +{{% cs-module name="room_upgrades" %}} +{{% cs-module name="server_notices" %}} +{{% cs-module name="moderation_policies" %}} +{{% cs-module name="spaces" %}} +{{% cs-module name="event_replacements" %}} +{{% cs-module name="event_annotations" %}} +{{% cs-module name="threading" %}} +{{% cs-module name="reference_relations" %}} diff --git a/content/client-server-api/modules/account_data.md b/content/client-server-api/modules/account_data.md index 12233bcd..1f1e5b8c 100644 --- a/content/client-server-api/modules/account_data.md +++ b/content/client-server-api/modules/account_data.md @@ -16,7 +16,7 @@ data with the same `type`. The client receives the account data as events in the `account_data` sections of a [`/sync`](#get_matrixclientv3sync) response. -These events can also be received in a `/events` response or in the +These events can also be received in a [`/events`](#get_matrixclientv3events) response or in the `account_data` section of a room in a `/sync` response. `m.tag` events appearing in `/events` will have a `room_id` with the room the tags are for. @@ -26,6 +26,15 @@ These events can also be received in a `/events` response or in the #### Server Behaviour -Servers MUST reject clients from setting account data for event types -that the server manages. Currently, this only includes -[m.fully\_read](#mfully_read). +Servers MUST reject setting account data for event types +that the server manages by using a 405 error response. +Currently, this only includes [`m.fully_read`](#mfully_read) +and [`m.push_rules`](#push-rules-events). This applies to +both global and room-specific account data. + +{{% boxes/note %}} +{{% changed-in v="1.10" %}} `m.push_rules` was added to the rejection +list. +{{% /boxes/note %}} + +Servers must allow clients to read the above event types as normal. diff --git a/content/client-server-api/modules/content_repo.md b/content/client-server-api/modules/content_repo.md index cef70b3d..c70d04fc 100644 --- a/content/client-server-api/modules/content_repo.md +++ b/content/client-server-api/modules/content_repo.md @@ -16,26 +16,69 @@ When serving content, the server SHOULD provide a `Content-Security-Policy` header. The recommended policy is `sandbox; default-src 'none'; script-src 'none'; plugin-types application/pdf; style-src 'unsafe-inline'; object-src 'self';`. -{{% boxes/added-in-paragraph %}} -{{< added-in v="1.4" >}} The server SHOULD additionally provide +{{% added-in v="1.4" %}} The server SHOULD additionally provide `Cross-Origin-Resource-Policy: cross-origin` when serving content to allow (web) clients to access restricted APIs such as `SharedArrayBuffer` when interacting with the media repository. -{{% /boxes/added-in-paragraph %}} + +{{% changed-in v="1.11" %}} The unauthenticated download endpoints have been +deprecated in favour of newer, authenticated, ones. This change includes updating +the paths of all media endpoints from `/_matrix/media/*` to `/_matrix/client/{version}/media/*`, +with the exception of the `/upload` and `/create` endpoints. The upload/create +endpoints are expected to undergo a similar transition in a later version of the +specification. #### Matrix Content (`mxc://`) URIs Content locations are represented as Matrix Content (`mxc://`) URIs. They look like: - mxc:/// +``` +mxc:/// - : The name of the homeserver where this content originated, e.g. matrix.org - : An opaque ID which identifies the content. + : The name of the homeserver where this content originated, e.g. matrix.org + : An opaque ID which identifies the content. +``` -#### Client behaviour +#### Client behaviour {id="content-repo-client-behaviour"} -Clients can upload and download content using the following HTTP APIs. +Clients can access the content repository using the following endpoints. + +{{% changed-in v="1.11" %}} A number of endpoints under the /_matrix/media hierarchy +have been deprecated and replaced with new endpoints which require authentication. +The deprecated endpoints are marked in the section below. + +{{% boxes/warning %}} +By Matrix 1.12, servers SHOULD "freeze" the deprecated, unauthenticated, endpoints +to prevent newly-uploaded media from being downloaded. This SHOULD mean that any +media uploaded *before* the freeze remains accessible via the deprecated endpoints, +and any media uploaded *after* (or *during*) the freeze SHOULD only be accessible +through the new, authenticated, endpoints. For remote media, "newly-uploaded" is +determined by the date the cache was populated. This may mean the media is older +than the freeze, but because the server had to re-download it, it is now considered +"new". + +Clients SHOULD update to support the authenticated endpoints before servers freeze +unauthenticated access. + +Servers SHOULD consider their local ecosystem impact before enacting a freeze. +This could mean ensuring their users' typical clients support the new endpoints +when available, or updating bridges to start using media proxies. + +In addition to the above, servers SHOULD exclude [IdP icons used in the `m.login.sso` flow](/client-server-api/#definition-mloginsso-flow-schema) +from the freeze. See the `m.login.sso` flow schema for details. + +An *example* timeline for a server may be: + +* Matrix 1.11 release: Clients begin supporting authenticated media. +* Matrix 1.12 release: Servers freeze unauthenticated media access. + * Media uploaded prior to this point still works with the deprecated endpoints. + * Newly uploaded (or cached) media *only* works on the authenticated endpoints. + +Matrix 1.12 is expected to be released in the July-September 2024 calendar quarter. +{{% /boxes/warning %}} + +{{% http-api spec="client-server" api="authed-content-repo" %}} {{% http-api spec="client-server" api="content-repo" %}} @@ -119,3 +162,50 @@ Homeservers have additional content-specific concerns: - Clients or remote homeservers may try to upload malicious files targeting vulnerabilities in either the homeserver thumbnailing or the client decoders. + +##### Serving inline content + +Clients with insecure configurations may be vulnerable to Cross-Site Scripting +attacks when served media with a `Content-Disposition` of `inline`. Clients +SHOULD NOT be hosted on the same domain as the media endpoints for the homeserver +to mitigate most of this risk. Servers SHOULD restrict `Content-Type` headers to +one of the following values when serving content with `Content-Disposition: inline`: + +* `text/css` +* `text/plain` +* `text/csv` +* `application/json` +* `application/ld+json` +* `image/jpeg` +* `image/gif` +* `image/png` +* `image/apng` +* `image/webp` +* `image/avif` +* `video/mp4` +* `video/webm` +* `video/ogg` +* `video/quicktime` +* `audio/mp4` +* `audio/webm` +* `audio/aac` +* `audio/mpeg` +* `audio/ogg` +* `audio/wave` +* `audio/wav` +* `audio/x-wav` +* `audio/x-pn-wav` +* `audio/flac` +* `audio/x-flac` + +These types are unlikely to cause Cross-Site Scripting issues when a `Content-Type` +header is provided, as clients will only try to render the data using that content +type. For example, if a HTML file is uploaded with a `Content-Type` of `image/png`, +clients will just assume that the image is corrupted, and won't render it as a +HTML page. Therefore, there is no risk in trusting the user-defined content type, +as long as the `Content-Disposition` is calculated based on that type. + +Clients SHOULD NOT rely on servers returning `inline` rather than `attachment` +on [`/download`](#get_matrixclientv1mediadownloadservernamemediaid). Server implementations might decide out of an abundance of +caution that all downloads are responded to with `attachment`, regardless of +content type - clients should not be surprised by this behaviour. diff --git a/content/client-server-api/modules/end_to_end_encryption.md b/content/client-server-api/modules/end_to_end_encryption.md index f2f75705..49b053f6 100644 --- a/content/client-server-api/modules/end_to_end_encryption.md +++ b/content/client-server-api/modules/end_to_end_encryption.md @@ -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. | | 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: @@ -150,7 +151,9 @@ JSON](/appendices/#signing-json). One-time and fallback keys are also uploaded to the homeserver using the [`/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 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 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. -12. Both Alice and Bob's devices perform an Elliptic-curve - Diffie-Hellman - (*ECDH(KAprivate*, *KBpublic*)), - using the result as the shared secret. +12. Both Alice's and Bob's devices perform an Elliptic-curve Diffie-Hellman using + their private ephemeral key, and the other device's ephemeral public key + (*ECDH(KAprivate*, *KBpublic*) + for Alice's device and + *ECDH(KBprivate*, *KApublic*) + 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 derived from the shared key using one of the methods in this section. If multiple SAS methods are available, clients should allow @@ -669,7 +674,7 @@ The process between Alice and Bob verifying each other would be: their devices if they match or not. 15. Assuming they match, Alice and Bob's devices each calculate Message Authentication Codes (MACs) for: - * Each of the keys that they wish the other user to verify (usually their + * Each of the keys that they wish the other user to verify (usually their device ed25519 key and their master cross-signing key). * The complete list of key IDs that they wish the other user to verify. @@ -833,15 +838,15 @@ is the concatenation of: - The Device ID of the device which sent the `m.key.verification.start` message, followed by `|`. - The public key from the `m.key.verification.key` message sent by - the device which sent the `m.key.verification.start` message, - followed by `|`. + the device which sent the `m.key.verification.start` message, encoded as + unpadded base64, followed by `|`. - The Matrix ID of the user who sent the `m.key.verification.accept` message, followed by `|`. - The Device ID of the device which sent the `m.key.verification.accept` message, followed by `|`. - The public key from the `m.key.verification.key` message sent by - the device which sent the `m.key.verification.accept` message, - followed by `|`. + the device which sent the `m.key.verification.accept` message, encoded as + unpadded base64, followed by `|`. - The `transaction_id` being used. When the `key_agreement_protocol` is the deprecated method `curve25519`, @@ -1174,10 +1179,16 @@ The process between Alice and Bob verifying each other would be: ###### QR code format -The QR codes to be displayed and scanned using this format will encode binary -strings in the general form: +The QR codes to be displayed and scanned MUST be +compatible with [ISO/IEC 18004:2015](https://www.iso.org/standard/62021.html) and +contain a single segment that uses the byte mode encoding. -- the ASCII string `MATRIX` +The error correction level can be chosen by the device displaying the QR code. + +The binary segment MUST be of the following form: + +- the string `MATRIX` encoded as one ASCII byte per character (i.e. `0x4D`, + `0x41`, `0x54`, `0x52`, `0x49`, `0x58`) - one byte indicating the QR code version (must be `0x02`) - one byte indicating the QR code verification mode. Should be one of the following values: @@ -1189,22 +1200,23 @@ strings in the general form: request event, encoded as: - two bytes in network byte order (big-endian) indicating the length in bytes of the ID as a UTF-8 string - - the ID as a UTF-8 string + - the ID encoded as a UTF-8 string - the first key, as 32 bytes. The key to use depends on the mode field: - if `0x00` or `0x01`, then the current user's own master cross-signing public key - - if `0x02`, then the current device's device key + - if `0x02`, then the current device's Ed25519 signing key - the second key, as 32 bytes. The key to use depends on the mode field: - if `0x00`, then what the device thinks the other user's master - cross-signing key is - - if `0x01`, then what the device thinks the other device's device key is - - if `0x02`, then what the device thinks the user's master cross-signing key - is -- a random shared secret, as a byte string. It is suggested to use a secret + cross-signing public key is + - if `0x01`, then what the device thinks the other device's Ed25519 signing + public key is + - if `0x02`, then what the device thinks the user's master cross-signing public + key is +- a random shared secret, as a sequence of bytes. It is suggested to use a secret that is about 8 bytes long. Note: as we do not share the length of the secret, and it is not a fixed size, clients will just use the remainder of - binary string as the shared secret. + binary segment as the shared secret. -For example, if Alice displays a QR code encoding the following binary string: +For example, if Alice displays a QR code encoding the following binary data: ``` "MATRIX" |ver|mode| len | event ID @@ -1266,10 +1278,10 @@ tries to read a message that it does not have keys for, it may request the key from the server and decrypt it. Backups are per-user, and users may replace backups with new backups. -In contrast with [Key requests](#key-requests), Server-side key backups -do not require another device to be online from which to request keys. -However, as the session keys are stored on the server encrypted, it -requires users to enter a decryption key to decrypt the session keys. +In contrast with [key requests](#key-requests), server-side key backups do not +require another device to be online from which to request keys. However, as +the session keys are stored on the server encrypted, the client requires a +[decryption key](#decryption-key) to decrypt the session keys. To create a backup, a client will call [POST /\_matrix/client/v3/room\_keys/version](#post_matrixclientv3room_keysversion) and define how the keys are to @@ -1290,7 +1302,7 @@ Clients must only store keys in backups after they have ensured that the - checking that it is signed by the user's [master cross-signing key](#cross-signing) or by a verified device belonging to the same user, or -- by deriving the public key from a private key that it obtained from a trusted +- deriving the public key from a private key that it obtained from a trusted source. Trusted sources for the private key include the user entering the key, retrieving the key stored in [secret storage](#secret-storage), or obtaining the key via [secret sharing](#sharing) from a verified device @@ -1307,31 +1319,24 @@ replace it with the new key based on the key metadata as follows: - and finally, if `is_verified` and `first_message_index` are equal, then it will keep the key with a lower `forwarded_count`. -###### Recovery key +###### Decryption key -If the recovery key (the private half of the backup encryption key) is -presented to the user to save, it is presented as a string constructed -as follows: +Normally, the decryption key (i.e. the secret part of the encryption key) is +stored on the server or shared with other devices using the [Secrets](#secrets) +module. When doing so, it is identified using the name `m.megolm_backup.v1`, +and the key is base64-encoded before being encrypted. -1. The 256-bit curve25519 private key is prepended by the bytes `0x8B` - and `0x01` -2. All the bytes in the string above, including the two header bytes, - are XORed together to form a parity byte. This parity byte is - appended to the byte string. -3. The byte string is encoded using base58, using the same [mapping as - is used for Bitcoin - addresses](https://en.bitcoin.it/wiki/Base58Check_encoding#Base58_symbol_chart), - that is, using the alphabet - `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`. -4. A space should be added after every 4th character. +If the backup decryption key is given directly to the user, the key should be +presented as a string using the common [cryptographic key +representation](/appendices/#cryptographic-key-representation). -When reading in a recovery key, clients must disregard whitespace, and -perform the reverse of steps 1 through 3. - -The recovery key can also be stored on the server or shared with other devices -using the [Secrets](#secrets) module. When doing so, it is identified using the -name `m.megolm_backup.v1`, and the key is base64-encoded before being -encrypted. +{{% boxes/note %}} +The backup decryption key was previously referred to as a "recovery +key". However, this conflicted with common practice in client user +interfaces, which often use the term "recovery key" to refer to the [secret +storage](#storage) key. The term "recovery key" is no longer used in this +specification. +{{% /boxes/note %}} ###### Backup algorithm: `m.megolm_backup.v1.curve25519-aes-sha2` @@ -1344,7 +1349,7 @@ the following format: The `session_data` field in the backups is constructed as follows: 1. Encode the session key to be backed up as a JSON object using the - `SessionData` format defined below. + `BackedUpSessionData` format defined below. 2. Generate an ephemeral curve25519 key, and perform an ECDH with the ephemeral key and the backup's public key to generate a shared @@ -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, becomes the `ciphertext` property of the `session_data`. -5. Pass the raw encrypted data (prior to base64 encoding) through - HMAC-SHA-256 using the MAC key generated above. The first 8 bytes of - the resulting MAC are base64-encoded, and become the `mac` property - of the `session_data`. +5. Pass an empty string through HMAC-SHA-256 using the MAC key generated above. + The first 8 bytes of the resulting MAC are base64-encoded, and become the + `mac` property 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" %}} @@ -1414,7 +1427,7 @@ user-supplied passphrase, and is created as follows: ###### Key export format -The exported sessions are formatted as a JSON array of `SessionData` +The exported sessions are formatted as a JSON array of `ExportedSessionData` objects described as follows: {{% definition path="api/client-server/definitions/megolm_export_session_data" %}} @@ -1523,9 +1536,11 @@ claiming to have sent messages which they didn't. `sender` must correspond to the user who sent the event, `recipient` to the local user, and `recipient_keys` to the local ed25519 key. -Clients must confirm that the `sender_key` and the `ed25519` field value -under the `keys` property match the keys returned by [`/keys/query`](/client-server-api/#post_matrixclientv3keysquery) for -the given user, and must also verify the signature of the keys from the +Clients must confirm that the `sender_key` property in the cleartext +`m.room.encrypted` event body, and the `keys.ed25519` property in the +decrypted plaintext, match the keys returned by +[`/keys/query`](#post_matrixclientv3keysquery) for +the given user. Clients must also verify the signature of the keys from the `/keys/query` response. Without this check, a client cannot be sure that the sender device owns the private part of the ed25519 key it claims to have in the Olm payload. This is crucial when the ed25519 key corresponds @@ -1765,9 +1780,9 @@ Example response: ], }, "device_one_time_keys_count": { - "curve25519": 10, "signed_curve25519": 20 - } + }, + "device_unused_fallback_key_types": ["signed_curve25519"] } ``` diff --git a/content/client-server-api/modules/event_annotations.md b/content/client-server-api/modules/event_annotations.md index 661d8001..6bcfb95d 100644 --- a/content/client-server-api/modules/event_annotations.md +++ b/content/client-server-api/modules/event_annotations.md @@ -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. 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 contains the emoji being used. diff --git a/content/client-server-api/modules/event_replacements.md b/content/client-server-api/modules/event_replacements.md index 9afe304e..90c67ecf 100644 --- a/content/client-server-api/modules/event_replacements.md +++ b/content/client-server-api/modules/event_replacements.md @@ -188,7 +188,7 @@ replacement event. ##### Server-side aggregation of `m.replace` relationships -{{< changed-in v="1.7" >}} +{{% changed-in v="1.7" %}} Note that there can be multiple events with an `m.replace` relationship to a given event (for example, if an event is edited multiple times). These should @@ -309,7 +309,7 @@ for re-notifying if the sending client feels a large enough revision was made). For example, if there is an event mentioning Alice: -```json5 +```json { "event_id": "$original_event", "type": "m.room.message", @@ -324,7 +324,7 @@ For example, if there is an event mentioning Alice: And an edit to also mention Bob: -```json5 +```json { "content": { "body": "* Hello Alice & Bob!", @@ -362,21 +362,19 @@ property under `m.new_content`. #### Edits of replies -Some particular constraints apply to events which replace a -[reply](#rich-replies). In particular: +A particular constraint applies to events which replace a [reply](#rich-replies): +in contrast to the original reply, there should be no `m.in_reply_to` property +in the the `m.relates_to` object, since it would be redundant (see +[Applying `m.new_content`](#applying-mnew_content) above, which notes that the +original event's `m.relates_to` is preserved), as well as being contrary to the +spirit of the event relationships mechanism which expects only one "parent" per +event. - * In contrast to the original reply, there should be no `m.in_reply_to` - property in the the `m.relates_to` object, since it would be redundant (see - [Applying `m.new_content`](#applying-mnew_content) above, which notes that - the original event's `m.relates_to` is preserved), as well as being contrary - to the spirit of the event relationships mechanism which expects only one - "parent" per event. - - * `m.new_content` should **not** contain any [reply - fallback](#fallbacks-for-rich-replies), - since it is assumed that any client which can handle edits can also display - replies natively. However, the `content` of the replacement event should provide - fallback content for clients which support neither rich replies nor edits. +{{% boxes/note %}} +{{% changed-in v="1.13" %}} +In previous versions of the specification, events which replace a [reply](#rich-replies) +could include a fallback in the `content`. This is no longer the case. +{{% /boxes/note %}} An example of an edit to a reply is as follows: @@ -385,15 +383,11 @@ An example of an edit to a reply is as follows: "type": "m.room.message", // irrelevant fields not shown "content": { - "body": "> <@alice:example.org> question\n\n* reply", + "body": "* reply", "msgtype": "m.text", - "format": "org.matrix.custom.html", - "formatted_body": "
In reply to @alice:example.org
question
* reply", "m.new_content": { "body": "reply", "msgtype": "m.text", - "format": "org.matrix.custom.html", - "formatted_body": "reply" }, "m.relates_to": { "rel_type": "m.replace", diff --git a/content/client-server-api/modules/guest_access.md b/content/client-server-api/modules/guest_access.md index 873908bb..ada9e71e 100644 --- a/content/client-server-api/modules/guest_access.md +++ b/content/client-server-api/modules/guest_access.md @@ -33,17 +33,20 @@ rather than allowing all homeservers to enforce the rules on each other. #### Client behaviour The following API endpoints are allowed to be accessed by guest accounts -for retrieving events: +for retrieving events and associated media: * [GET /rooms/{roomId}/state](#get_matrixclientv3roomsroomidstate) * [GET /rooms/{roomId}/context/{eventId}](#get_matrixclientv3roomsroomidcontexteventid) * [GET /rooms/{roomId}/event/{eventId}](#get_matrixclientv3roomsroomideventeventid) * [GET /rooms/{roomId}/state/{eventType}/{stateKey}](#get_matrixclientv3roomsroomidstateeventtypestatekey) * [GET /rooms/{roomId}/messages](#get_matrixclientv3roomsroomidmessages) -* {{< added-in v="1.1" >}} [GET /rooms/{roomId}/members](#get_matrixclientv3roomsroomidmembers) +* {{% added-in v="1.1" %}} [GET /rooms/{roomId}/members](#get_matrixclientv3roomsroomidmembers) * [GET /rooms/{roomId}/initialSync](#get_matrixclientv3roomsroomidinitialsync) * [GET /sync](#get_matrixclientv3sync) * [GET /events](#get_matrixclientv3events) as used for room previews. +* {{% added-in v="1.12" %}} [GET /media/download/{serverName}/{mediaId}](#get_matrixclientv1mediadownloadservernamemediaid) +* {{% added-in v="1.12" %}} [GET /media/download/{serverName}/{mediaId}/{fileName}](#get_matrixclientv1mediadownloadservernamemediaidfilename) +* {{% added-in v="1.12" %}} [GET /media/thumbnail/{serverName}/{mediaId}](#get_matrixclientv1mediathumbnailservernamemediaid) The following API endpoints are allowed to be accessed by guest accounts for sending events: @@ -52,9 +55,9 @@ for sending events: * [POST /rooms/{roomId}/leave](#post_matrixclientv3roomsroomidleave) * [PUT /rooms/{roomId}/send/{eventType}/{txnId}](#put_matrixclientv3roomsroomidsendeventtypetxnid) - * {{< changed-in v="1.2" >}} Guests can now send *any* event type rather than just `m.room.message` events. + * {{% changed-in v="1.2" %}} Guests can now send *any* event type rather than just `m.room.message` events. -* {{< added-in v="1.2" >}} [PUT /rooms/{roomId}/state/{eventType}/{stateKey}](#put_matrixclientv3roomsroomidstateeventtypestatekey) +* {{% added-in v="1.2" %}} [PUT /rooms/{roomId}/state/{eventType}/{stateKey}](#put_matrixclientv3roomsroomidstateeventtypestatekey) * [PUT /sendToDevice/{eventType}/{txnId}](#put_matrixclientv3sendtodeviceeventtypetxnid) The following API endpoints are allowed to be accessed by guest accounts @@ -64,7 +67,7 @@ for their own account maintenance: * [GET /devices](#get_matrixclientv3devices) * [GET /devices/{deviceId}](#get_matrixclientv3devicesdeviceid) * [PUT /devices/{deviceId}](#put_matrixclientv3devicesdeviceid) -* {{< added-in v="1.2" >}} [GET /account/whoami](#get_matrixclientv3accountwhoami) +* {{% added-in v="1.2" %}} [GET /account/whoami](#get_matrixclientv3accountwhoami) The following API endpoints are allowed to be accessed by guest accounts for end-to-end encryption: diff --git a/content/client-server-api/modules/ignore_users.md b/content/client-server-api/modules/ignore_users.md index f682d9e6..f87beccf 100644 --- a/content/client-server-api/modules/ignore_users.md +++ b/content/client-server-api/modules/ignore_users.md @@ -13,10 +13,10 @@ and servers can implement the ignoring of users. To ignore a user, effectively blocking them, the client should add the target user to the `m.ignored_user_list` event in their account data -using [`/user//account_data/`](/client-server-api/#put_matrixclientv3useruseridaccount_datatype). Once ignored, the client will no longer receive events sent by +using [`/user//account_data/`](#put_matrixclientv3useruseridaccount_datatype). Once ignored, the client will no longer receive events sent by that user, with the exception of state events. The client should either hide previous content sent by the newly ignored user or perform a new -`/sync` with no previous token. +[`/sync`](#get_matrixclientv3sync) with no previous token. Invites to new rooms by ignored users will not be sent to the client. The server may optionally reject the invite on behalf of the client. diff --git a/content/client-server-api/modules/instant_messaging.md b/content/client-server-api/modules/instant_messaging.md index 5fcf379f..d5c0cb6a 100644 --- a/content/client-server-api/modules/instant_messaging.md +++ b/content/client-server-api/modules/instant_messaging.md @@ -27,18 +27,41 @@ instead. Some message types support HTML in the event content that clients should prefer to display if available. Currently `m.text`, `m.emote`, `m.notice`, -and `m.key.verification.request` support an additional `format` parameter of -`org.matrix.custom.html`. When this field is present, a `formatted_body` -with the HTML must be provided. The plain text version of the HTML -should be provided in the `body`. +`m.image`, `m.file`, `m.audio`, `m.video` and `m.key.verification.request` +support an additional `format` parameter of `org.matrix.custom.html`. When this +field is present, a `formatted_body` with the HTML must be provided. The plain +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, HTML injection, and similar attacks. The strongly suggested set of HTML tags to permit, denying the use and rendering of anything else, is: -`font`, `del`, `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `blockquote`, `p`, -`a`, `ul`, `ol`, `sup`, `sub`, `li`, `b`, `i`, `u`, `strong`, `em`, -`strike`, `code`, `hr`, `br`, `div`, `table`, `thead`, `tbody`, `tr`, -`th`, `td`, `caption`, `pre`, `span`, `img`, `details`, `summary`. +`del`, `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `blockquote`, `p`, `a`, `ul`, +`ol`, `sup`, `sub`, `li`, `b`, `i`, `u`, `strong`, `em`, `s`, `code`, +`hr`, `br`, `div`, `table`, `thead`, `tbody`, `tr`, `th`, `td`, +`caption`, `pre`, `span`, `img`, `details`, `summary`. + +{{% boxes/note %}} +{{% added-in v="1.10" %}} +HTML features MAY be deprecated and replaced by their modern equivalent without +requiring a [Spec Change Proposal](/proposals) when they are deprecated in the +[WHATWG HTML Living Standard](https://html.spec.whatwg.org/multipage/). +{{% /boxes/note %}} + +{{% boxes/note %}} +{{% changed-in v="1.10" %}} +In previous versions of the specification, the `font` tag was suggested with the +`data-mx-bg-color`, `data-mx-color` and `color` attributes. This tag is now +deprecated in favor of the `span` tag with the `data-mx-bg-color` and +`data-mx-color` attributes in new messages. +{{% /boxes/note %}} Not all attributes on those tags should be permitted as they may be avenues for other disruption attempts, such as adding `onclick` handlers @@ -50,12 +73,12 @@ the tag. | Tag | Permitted Attributes | |--------|--------------------------------------------------------------------------------------------------------------------------------------------| -| `font` | `data-mx-bg-color`, `data-mx-color`, `color` | -| `span` | `data-mx-bg-color`, `data-mx-color`, `data-mx-spoiler` (see [spoiler messages](#spoiler-messages)) | -| `a` | `name`, `target`, `href` (provided the value is not relative and has a scheme matching one of: `https`, `http`, `ftp`, `mailto`, `magnet`) | +| `span` | `data-mx-bg-color`, `data-mx-color`, `data-mx-spoiler` (see [spoiler messages](#spoiler-messages)), `data-mx-maths` (see [mathematical messages](#mathematical-messages)) | +| `a` | `target`, `href` (provided the value is not relative and has a scheme matching one of: `https`, `http`, `ftp`, `mailto`, `magnet`) | | `img` | `width`, `height`, `alt`, `title`, `src` (provided it is a [Matrix Content (`mxc://`) URI](#matrix-content-mxc-uris)) | | `ol` | `start` | | `code` | `class` (only classes which start with `language-` for syntax highlighting) | +| `div` | `data-mx-maths` (see [mathematical messages](#mathematical-messages)) | Additionally, web clients should ensure that *all* `a` tags get a `rel="noopener"` to prevent the target page from referencing the @@ -75,14 +98,12 @@ having appropriate closing tags, appropriate attributes (considering the custom ones defined in this specification), and generally valid structure. -A special tag, `mx-reply`, may appear on rich replies (described below) -and should be allowed if, and only if, the tag appears as the very first -tag in the `formatted_body`. The tag cannot be nested and cannot be -located after another tag in the tree. Because the tag contains HTML, an -`mx-reply` is expected to have a partner closing tag and should be -treated similar to a `div`. Clients that support rich replies will end -up stripping the tag and its contents and therefore may wish to exclude -the tag entirely. +{{% boxes/note %}} +{{% changed-in v="1.13" %}} +In previous versions of the specification, [rich replies](#rich-replies) could +use a special tag, `mx-reply`. This is no longer the case. Clients SHOULD strip +this tag and its content. See the "Rich replies" section for more information. +{{% /boxes/note %}} {{% boxes/note %}} A future iteration of the specification will support more powerful and @@ -320,6 +341,107 @@ 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 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 cat 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. + +##### Mathematical messages + +{{% added-in v="1.11" %}} + +Users might want to send mathematical notations in their messages. + +To send mathematical notations clients MUST use the `formatted_body` and +therefore the `org.matrix.custom.html` format, described above. This makes +mathematical notations valid on any `msgtype` which can support this format +appropriately. + +Mathematical notations themselves use the `span` or `div` tags, depending +whether the notation should be presented inline or not. The mathematical +notation is written in [LaTeX](https://www.latex-project.org/) format using the +`data-mx-maths` attribute. + +The contents of the tag should be a fallback representation for clients that +cannot render the LaTeX format. The fallback representation could be, for +example, an image, or an HTML approximation, or the raw LaTeX source. When using +an image as a fallback, the sending client should be aware of issues that may +arise from the receiving client using a different background colour. The `body` +should include a textual representation of the notation. + +An example of a mathematical notation is: + +```json +{ + "msgtype": "m.text", + "format": "org.matrix.custom.html", + "body": "This is an equation: sin(x)=a/b.", + "formatted_body": "This is an equation: + + sin(x)=a/b + " +} +``` + +The LaTeX format is poorly defined and has several extensions, so if a client +encounters syntax that it cannot render, it SHOULD present the fallback +representation instead. Clients SHOULD, however, aim to support, at minimum, the +basic [LaTeX2e](https://www.latex-project.org/) maths commands and the +[TeX](https://tug.org/) maths commands, with the possible exception of commands +that could be security risks. + +{{% boxes/warning %}} +In general, LaTeX places a heavy burden on client authors to ensure that it is +processed safely. Certain commands, such as [those that can create macros](https://katex.org/docs/supported#macros), +are potentially dangerous. Clients should either decline to process those +commands, or should take care to ensure that they are handled in safe ways (such +as by limiting recursion). In general, LaTeX commands should be filtered by +allowing known-good commands rather than forbidding known-bad commands. + +Therefore, clients should not render mathematics by calling a LaTeX compiler +without proper sandboxing, as those executables were not written to handle +untrusted input. Some LaTeX rendering libraries are better suited for that by +allowing only a subset of LaTeX and enforcing recursion limits. +{{% /boxes/warning %}} + #### Server behaviour Homeservers SHOULD reject `m.room.message` events which don't have a diff --git a/content/client-server-api/modules/mentions.md b/content/client-server-api/modules/mentions.md index 32309740..0cdbad77 100644 --- a/content/client-server-api/modules/mentions.md +++ b/content/client-server-api/modules/mentions.md @@ -13,6 +13,20 @@ the event to reference the entity being mentioned. {{% 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 Alice!", + "m.mentions": { + "user_ids": ["@alice:example.org"] + } +} +``` + 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. Users should not add their own Matrix ID to the `m.mentions` property as outgoing diff --git a/content/client-server-api/modules/moderation_policies.md b/content/client-server-api/modules/moderation_policies.md index 82a05963..2912d164 100644 --- a/content/client-server-api/modules/moderation_policies.md +++ b/content/client-server-api/modules/moderation_policies.md @@ -13,7 +13,7 @@ deciding what content is undesirable for any particular entity and should instead be empowering those entities to make their own decisions. As such, a generic framework for communicating "moderation policy lists" or "moderation policy rooms" is described. Note that this module only -describes the data structures and not how they should be interpreting: +describes the data structures and not how they should be interpreted: the entity making the decisions on filtering is best positioned to interpret the rules how it sees fit. diff --git a/content/client-server-api/modules/push.md b/content/client-server-api/modules/push.md index d1855f58..15639995 100644 --- a/content/client-server-api/modules/push.md +++ b/content/client-server-api/modules/push.md @@ -184,11 +184,13 @@ they are represented as a dictionary with a key equal to their name and other keys as their parameters, e.g. `{ "set_tweak": "sound", "value": "default" }`. -{{% boxes/note %}} +###### Historical Actions + Older versions of the Matrix specification included the `dont_notify` and -`coalesce` actions. These should both be considered no-ops (ignored, not -rejected) if received from a client. -{{% /boxes/note %}} +`coalesce` actions. Clients and homeservers MUST ignore these actions, for +instance, by stripping them from actions arrays they encounter. This means, +for example, that a rule with `["dont_notify"]` actions MUST be equivalent +to a rule with an empty actions array. ##### Conditions @@ -454,7 +456,7 @@ Definition: { "kind": "event_match", "key": "content.msgtype", - "pattern": "m.notice", + "pattern": "m.notice" } ], "actions": [] @@ -521,9 +523,9 @@ Definition: } ``` - **`.m.rule.is_user_mention`** + **`.m.rule.is_user_mention`** -{{< added-in v="1.7" >}} +{{% added-in v="1.7" %}} Matches any message which contains the user's Matrix ID in the list of `user_ids` under the `m.mentions` property. @@ -555,7 +557,7 @@ Definition: } ``` - **`.m.rule.contains_display_name`** + **`.m.rule.contains_display_name`** {{% changed-in v="1.7" %}} @@ -590,9 +592,9 @@ Definition: } ``` - **`.m.rule.is_room_mention`** + **`.m.rule.is_room_mention`** -{{< added-in v="1.7" >}} +{{% added-in v="1.7" %}} Matches any message from a sender with the proper power level with the `room` property of the `m.mentions` property set to `true`. @@ -624,7 +626,7 @@ Definition: } ``` - **`.m.rule.roomnotif`** + **`.m.rule.roomnotif`** {{% changed-in v="1.7" %}} @@ -662,7 +664,7 @@ Definition: } ``` -**`.m.rule.tombstone`** +**`.m.rule.tombstone`** Matches any state event whose type is `m.room.tombstone`. This is intended to notify users of a room when it is upgraded, similar to what @@ -696,7 +698,7 @@ Definition: } ``` -**`.m.rule.reaction`** +**`.m.rule.reaction`** {{% added-in v="1.7" %}} @@ -750,9 +752,33 @@ 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 - **`.m.rule.contains_user_name`** + **`.m.rule.contains_user_name`** {{% changed-in v="1.7" %}} @@ -1018,7 +1044,7 @@ messages they have received. ##### Receiving notifications Servers MUST include the number of unread notifications in a client's -`/sync` stream, and MUST update it as it changes. Notifications are +[`/sync`](#get_matrixclientv3sync) stream, and MUST update it as it changes. Notifications are determined by the push rules which apply to an event. For encrypted events, the homeserver has limited access to the event content @@ -1046,16 +1072,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 behind the `m.read.private` receipt). -{{< added-in v="1.4" >}} When handling threaded read receipts, the server -is to partition the notification count to each thread (with the main timeline -being its own thread). To determine if an event is part of a thread the -server follows the [event relationship](#forming-relationships-between-events) -until it finds a thread root (as specified by the [threading module](#threading)), -however it is not recommended that the server traverse infinitely. Instead, -implementations are encouraged to do a maximum of 3 hops to find a thread -before deciding that the event does not belong to a thread. This is primarily -to ensure that future events, like `m.reaction`, are correctly considered -"part of" a given thread. +{{% added-in v="1.4" %}} When handling threaded read receipts, the server is to +partition the notification count to each thread (with the main timeline being +its own thread). To determine if an event is part of a thread the server follows +the [event relationship](#forming-relationships-between-events) until it finds a +thread root via an `m.thread` relation (as specified by the [threading +module](#threading)), however it is not recommended that the server traverse +infinitely. Instead, implementations are encouraged to do a maximum of 3 hops to +find a thread before deciding that the event does not belong to a thread. This +is primarily to ensure that future events, like `m.reaction`, are correctly +considered "part of" a given thread. #### Server behaviour @@ -1065,7 +1091,7 @@ users in the room (excluding the sender). This may result in: * Generating a new number of unread notifications for the user. * Making a request to the configured push gateway. -The updated notification count from a new event MUST appear in the same `/sync` +The updated notification count from a new event MUST appear in the same [`/sync`](#get_matrixclientv3sync) response as the event itself. #### Push Gateway behaviour diff --git a/content/client-server-api/modules/read_markers.md b/content/client-server-api/modules/read_markers.md index aa0baf47..960f50b7 100644 --- a/content/client-server-api/modules/read_markers.md +++ b/content/client-server-api/modules/read_markers.md @@ -1,5 +1,6 @@ +### Read and unread markers -### Fully read markers +#### Fully read markers The history for a given room may be split into three sections: messages the user has read (or indicated they aren't interested in them), @@ -8,7 +9,7 @@ user hasn't seen yet. The "fully read marker" (also known as a "read marker") marks the last event of the first section, whereas the user's read receipt marks the last event of the second section. -#### Events +##### Events The user's fully read marker is kept as an event in the room's [account data](#client-config). The event may be read to determine the user's @@ -22,13 +23,13 @@ should be considered to be the user's read receipt location. {{% event event="m.fully_read" %}} -#### Client behaviour +##### Client behaviour The client cannot update fully read markers by directly modifying the `m.fully_read` account data event. Instead, the client must make use of the read markers API to change the values. -{{< changed-in v="1.4" >}} `m.read.private` receipts can now be sent from +{{% changed-in v="1.4" %}} `m.read.private` receipts can now be sent from `/read_markers`. The read markers API can additionally update the user's read receipt @@ -41,7 +42,7 @@ might wish to save an extra HTTP call. Providing `m.read` and/or {{% http-api spec="client-server" api="read_markers" %}} -#### Server behaviour +##### Server behaviour The server MUST prevent clients from setting `m.fully_read` directly in room account data. The server must additionally ensure that it treats @@ -53,3 +54,46 @@ Upon updating the `m.fully_read` event due to a request to `/read_markers`, the server MUST send the updated account data event through to the client via the event stream (eg: `/sync`), provided any applicable filters are also satisfied. + +#### Unread markers + +{{% added-in v="1.12" %}} + +Clients may use "unread markers" to allow users to label rooms for later +attention irrespective of [read receipts](#receipts) or +[fully read markers](#fully-read-markers). + +##### Events + +The user's unread marker in a room is kept under an `m.marked_unread` +event in the room's [account data](#client-config). The event may be read +to determine the user's current unread marker state in the room. Just +like other account data events, the event will be pushed down the event +stream when updated. + +{{% event event="m.marked_unread" %}} + +##### Client behaviour + +Clients MUST update unread markers by directly modifying the `m.marked_unread` +room account data event. When marking a room as unread, clients SHOULD NOT change +the `m.fully_read` marker, so that the user's read position in the room is +retained. + +When the `unread` field is `true`, clients SHOULD visually annotate the room +to indicate that it is unread. Exactly how this is achieved is left as an +implementation detail. It is RECOMMENDED that clients use a treatment similar +to how they represent rooms with unread notifications. + +Clients SHOULD reset the unread marker by setting `unread` to `false` when +opening a room to display its timeline. + +Clients that offer functionality to mark a room as _read_ by sending a read +receipt for the last event, SHOULD reset the unread marker simultaneously. + +If the `m.marked_unread` event does not exist on the user's account data, +clients MUST behave as if `unread` was `false`. + +##### Server behaviour + +Servers have no additional requirements placed on them by this submodule. diff --git a/content/client-server-api/modules/receipts.md b/content/client-server-api/modules/receipts.md index 8cd4e9f6..f38e8611 100644 --- a/content/client-server-api/modules/receipts.md +++ b/content/client-server-api/modules/receipts.md @@ -1,7 +1,7 @@ ### Receipts -{{< changed-in v="1.4" >}} Added private read receipts. +{{% changed-in v="1.4" %}} Added private read receipts. This module adds in support for receipts. These receipts are a form of acknowledgement of an event. This module defines the `m.read` receipt @@ -19,7 +19,7 @@ that the user had read all events *up to* the referenced event. See the [Receiving notifications](#receiving-notifications) section for more information on how read receipts affect notification counts. -{{< added-in v="1.4" >}} Read receipts exist in three major forms: +{{% added-in v="1.4" %}} Read receipts exist in three major forms: * Unthreaded: Denotes a read-up-to receipt regardless of threads. This is how pre-threading read receipts worked. * Threaded, main timeline: Denotes a read-up-to receipt for events not in a @@ -31,7 +31,7 @@ Threaded read receipts are discussed in further detail [below](#threaded-read-re #### Events -{{< changed-in v="1.4" >}} Each `user_id`, `receipt_type`, and categorisation +{{% changed-in v="1.4" %}} Each `user_id`, `receipt_type`, and categorisation (unthreaded, or `thread_id`) tuple must be associated with only a single `event_id`. @@ -39,9 +39,9 @@ Threaded read receipts are discussed in further detail [below](#threaded-read-re #### Client behaviour -{{< changed-in v="1.4" >}} Altered to support threaded read receipts. +{{% changed-in v="1.4" %}} Altered to support threaded read receipts. -In `/sync`, receipts are listed under the `ephemeral` array of events +In [`/sync`](#get_matrixclientv3sync), receipts are listed under the `ephemeral` array of events for a given room. New receipts that come down the event streams are deltas which update existing mappings. Clients should replace older receipt acknowledgements based on `user_id`, `receipt_type`, and the @@ -137,26 +137,30 @@ 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 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: -* 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. +considered to be "in a thread" if: -Events not in a thread but still in the room are considered to be part of the -"main timeline", or a special thread with an ID of `main`. +* It has a `rel_type` of `m.thread`, or +* 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 relationships and solid lines showing topological ordering. -![threaded-dag](/diagrams/threaded-dag.png) +{{% diagram name="threaded-dag" alt="Diagram presenting a DAG with thread relationships as a single timeline" %}} This DAG can be represented as 3 threaded timelines, with `A` and `B` being thread roots: -![threaded-dag-threads](/diagrams/threaded-dag-threads.png) +{{% diagram name="threaded-dag-threads" alt="Diagram presenting a DAG with thread relationships as 3 related timelines" %}} With this, we can demonstrate that: * A threaded read receipt on `I` would mark `A`, `B`, and `I` as read. @@ -204,7 +208,7 @@ event when the user expands that thread. #### 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. Some receipts are sent across federation as EDUs with type `m.receipt`. The diff --git a/content/client-server-api/modules/report_content.md b/content/client-server-api/modules/report_content.md index 02ef002a..6f34e938 100644 --- a/content/client-server-api/modules/report_content.md +++ b/content/client-server-api/modules/report_content.md @@ -5,9 +5,6 @@ Users may encounter content which they find inappropriate and should be able to report it to the server administrators or room moderators for review. This module defines a way for users to report content. -Content is reported based upon a negative score, where -100 is "most -offensive" and 0 is "inoffensive". - #### Client behaviour {{% http-api spec="client-server" api="report_content" %}} @@ -18,3 +15,17 @@ Servers are free to handle the reported content however they desire. This may be a dedicated room to alert server administrators to the reported content or some other mechanism for notifying the appropriate people. + +Particularly during waves of harmful content, users may report whole +rooms instead of individual events. Server administrators and safety teams +should, therefore, be cautious not to shut down rooms that might otherwise +be legitimate. + +{{% changed-in v="1.8" %}} When processing event reports, servers MUST +verify that the reporting user is currently joined to the room the event +is in before accepting a report. + +{{% added-in v="1.13" %}} Contrarily, servers MUST NOT restrict room reports +based on whether or not the reporting user is joined to the room. This is +because users can be exposed to harmful content without being joined to a +room. For instance, through room directories or invites. diff --git a/content/client-server-api/modules/rich_replies.md b/content/client-server-api/modules/rich_replies.md index a0018630..5ad2a10e 100644 --- a/content/client-server-api/modules/rich_replies.md +++ b/content/client-server-api/modules/rich_replies.md @@ -1,14 +1,13 @@ ### Rich replies -{{% changed-in v="1.3" %}} - Rich replies are a special kind of [relationship](#forming-relationships-between-events) which effectively quotes the referenced event for the client to render/process how it wishes. They are normally used with [`m.room.message`](#mroommessage) events. {{% boxes/note %}} +{{% changed-in v="1.3" %}} Until v1.3 of the spec, rich replies were limited to `m.room.message` events which could represent an HTML-formatted body. As of v1.3 this is now expanded to *all* event types by dropping the requirement that an HTML-formatted body @@ -18,9 +17,24 @@ Additionally, a rich reply can reference any other event type as of v1.3. Previously, a rich reply could only reference another `m.room.message` event. {{% /boxes/note %}} -When possible, events SHOULD include a [fallback representation](#fallbacks-for-rich-replies) -to allow clients which do not render rich replies to still see something which -appears to be a quoted reply. +{{% boxes/note %}} +{{% changed-in v="1.13" %}} +In previous versions of the specification, rich replies could include a fallback +representation of the original message message in the `body` (using a prefix +sequence) and `formatted_body` (using a custom HTML element) for clients that do +not support rich replies. This is no longer the case, but clients SHOULD still +remove this fallback before rendering the event. + +To strip the fallback on the `body`, the client should iterate over each +line of the string, removing any lines that start with the fallback +prefix sequence (`> `, including the trailing space) and stopping when +a line is encountered without the prefix. + +To strip the fallback on the `formatted_body` of an `m.room.message` event with +a `format` of `org.matrix.custom.html`: if the`formatted_body` begins with an +`` start tag, the client should remove the entirety of the +`` element. +{{% /boxes/note %}} Though rich replies form a relationship to another event, they do not use `rel_type` to create this relationship. Instead, a subkey named `m.in_reply_to` @@ -31,7 +45,7 @@ the `rel_type` and `event_id` properties of `m.relates_to` become *optional*. An example reply would be: -```json5 +```json { "content": { "m.relates_to": { @@ -48,136 +62,6 @@ An example reply would be: Note that the `event_id` of the `m.in_reply_to` object has the same requirements as if it were to be under `m.relates_to` directly instead. -#### Fallbacks for rich replies - -Some clients may not have support for rich replies and therefore need a -fallback to use instead. Clients that do not support rich replies should -render the event as if rich replies were not special. - -Clients that do support rich replies SHOULD provide the fallback format on -replies, and MUST strip the fallback before rendering the reply. The -specific fallback text is different for each `msgtype`, however the -general format for the `body` is: - -```text -> <@alice:example.org> This is the original body - -This is where the reply goes -``` - -The `formatted_body`, if present and using an associated `format` of -`org.matrix.custom.html`, should use the following template: - -```html - -
- In reply to - @alice:example.org -
- -
-
-This is where the reply goes. -``` - -If the related event does not have a `formatted_body`, the event's -`body` should be considered after encoding any HTML special characters. -Note that the `href` in both of the anchors use a [matrix.to -URI](/appendices#matrixto-navigation). - -##### Stripping the fallback - -Clients which support rich replies MUST strip the fallback from the -event before rendering the event. This is because the text provided in -the fallback cannot be trusted to be an accurate representation of the -event. After removing the fallback, clients are recommended to represent -the event referenced by `m.in_reply_to` similar to the fallback's -representation, although clients do have creative freedom for their user -interface. Clients should prefer the `formatted_body` over the `body`, -just like with other `m.room.message` events. - -To strip the fallback on the `body`, the client should iterate over each -line of the string, removing any lines that start with the fallback -prefix ("> ", including the space, without quotes) and stopping when -a line is encountered without the prefix. This prefix is known as the -"fallback prefix sequence". - -To strip the fallback on the `formatted_body`, the client should remove -the entirety of the `mx-reply` tag. - -##### Fallback for `m.text`, `m.notice`, and unrecognised message types - -Using the prefix sequence, the first line of the related event's `body` -should be prefixed with the user's ID, followed by each line being -prefixed with the fallback prefix sequence. For example: - -```text -> <@alice:example.org> This is the first line -> This is the second line - -This is the reply -``` - -The `formatted_body` uses the template defined earlier in this section. - -##### Fallback for `m.emote` - -Similar to the fallback for `m.text`, each line gets prefixed with the -fallback prefix sequence. However an asterisk should be inserted before -the user's ID, like so: - -```text -> * <@alice:example.org> feels like today is going to be a great day - -This is the reply -``` - -The `formatted_body` has a subtle difference for the template where the -asterisk is also inserted ahead of the user's ID: - -```html - -
- In reply to - * @alice:example.org -
- -
-
-This is where the reply goes. -``` - -##### Fallback for `m.image`, `m.video`, `m.audio`, and `m.file` - -The related event's `body` would be a file name, which may not be very -descriptive. The related event should additionally not have a `format` -or `formatted_body` in the `content` - if the event does have a `format` -and/or `formatted_body`, those fields should be ignored. Because the -filename alone may not be descriptive, the related event's `body` should -be considered to be `"sent a file."` such that the output looks similar -to the following: - -```text -> <@alice:example.org> sent a file. - -This is the reply -``` -```html - -
- In reply to - @alice:example.org -
- sent a file. -
-
-This is where the reply goes. -``` - -For `m.image`, the text should be `"sent an image."`. For `m.video`, the -text should be `"sent a video."`. For `m.audio`, the text should be -`"sent an audio file"`. - #### Mentioning the replied to user In order to notify users of the reply, it may be desirable to include the `sender` @@ -186,7 +70,7 @@ of the replied to event and any users mentioned in that event. See An example including mentioning the original sender and other users: -```json5 +```json { "content": { "m.relates_to": { diff --git a/content/client-server-api/modules/room_previews.md b/content/client-server-api/modules/room_previews.md index 277f7c39..ef9238b2 100644 --- a/content/client-server-api/modules/room_previews.md +++ b/content/client-server-api/modules/room_previews.md @@ -21,7 +21,7 @@ Clients can of course also call other endpoints such as [GET and [GET /search](#post_matrixclientv3search) to access events outside the `/events` stream. -{{% http-api spec="client-server" api="peeking_events" %}} +{{% http-api spec="client-server" api="peeking_events" anchor_base="peeking" %}} #### Server behaviour diff --git a/content/client-server-api/modules/room_upgrades.md b/content/client-server-api/modules/room_upgrades.md index aacedf12..647fb377 100644 --- a/content/client-server-api/modules/room_upgrades.md +++ b/content/client-server-api/modules/room_upgrades.md @@ -30,7 +30,7 @@ server: 1. Checks that the user has permission to send `m.room.tombstone` events in the room. -2. {{< changed-in v="1.4" >}} Creates a replacement room with a `m.room.create` event containing a +2. {{% changed-in v="1.4" %}} Creates a replacement room with a `m.room.create` event containing a `predecessor` field, the applicable `room_version`, and a `type` field which is copied from the `predecessor` room. If no `type` is set on the previous room, no `type` is specified on the new room's create event diff --git a/content/client-server-api/modules/secrets.md b/content/client-server-api/modules/secrets.md index 2d12d488..3e586bc4 100644 --- a/content/client-server-api/modules/secrets.md +++ b/content/client-server-api/modules/secrets.md @@ -15,6 +15,9 @@ secret when storing, fetching, requesting, or sharing the secret. Secrets are plain strings; structured data can be stored by encoding it as a string. +The mechanism described in this section is known as "secure secret storage and +sharing", "SSSS", or "4S". + #### Storage When secrets are stored on the server, they are stored in the user's @@ -66,6 +69,70 @@ 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 Encrypted data is stored in the user's account data using the event @@ -82,7 +149,7 @@ of the data. | 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: @@ -147,58 +214,41 @@ HMAC-SHA-256. The secret is encrypted as follows: 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 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 differences in AES-CTR implementations), and use this as the AES - initialization vector. This becomes the `iv` property, encoded using - base64. -3. Encrypt the data using AES-CTR-256 using the AES key generated - above. This encrypted data, encoded using base64, becomes the - `ciphertext` property. -4. Pass the raw encrypted data (prior to base64 encoding) through - HMAC-SHA-256 using the MAC key generated above. The resulting MAC is - base64-encoded and becomes the `mac` property. + initialization vector (IV). + +3. Encrypt the data 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, 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` | Parameter | Type | Description |------------|---------|------------------------------------------------------------------------| -| iv | string | **Required.** The 16-byte initialization vector, encoded as base64. | -| ciphertext | string | **Required.** The AES-CTR-encrypted data, encoded as base64. | -| mac | string | **Required.** The MAC, 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. | +| 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 - 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: +For example, data encrypted using this algorithm could look like this: ```json { @@ -212,27 +262,13 @@ 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`, -it will be presented as a string constructed as follows: +the key should be presented as a string using the common [cryptographic key +representation](/appendices/#cryptographic-key-representation). -1. The key is prepended by the two bytes `0x8b` and `0x01` -2. All the bytes in the string above, including the two header bytes, - are XORed together to form a parity byte. This parity byte is - appended to the byte string. -3. The byte string is encoded using base58, using the same [mapping as - is used for Bitcoin - addresses](https://en.bitcoin.it/wiki/Base58Check_encoding#Base58_symbol_chart), - that is, using the alphabet - `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`. -4. The string is formatted into groups of four characters separated by - spaces. - -When decoding a raw key, the process should be reversed, with the -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 generated key. In this case, information on how to generate the key from diff --git a/content/client-server-api/modules/sso_login.md b/content/client-server-api/modules/sso_login.md index 95a3e23a..f50a2eb1 100644 --- a/content/client-server-api/modules/sso_login.md +++ b/content/client-server-api/modules/sso_login.md @@ -10,7 +10,7 @@ This module allows a Matrix homeserver to delegate user authentication to an external authentication server supporting one of these protocols. In this process, there are three systems involved: -- A Matrix client, using the APIs defined this specification, which +- A Matrix client, using the APIs defined in this specification, which is seeking to authenticate a user to a Matrix homeserver. - A Matrix homeserver, implementing the APIs defined in this specification, but which is delegating user authentication to the @@ -123,8 +123,8 @@ authentication is successful, the browser will be redirected to that For example, consider a web-based client at `https://client.example.com`, which wants to initiate SSO login on - the homeserver at `server.example.org`. It does this by storing the - homeserver name in a query parameter for the `redirectUrl`: it + the homeserver with [server name](/appendices/#server-name) `server.example.org`. It does this by storing the + server name in a query parameter for the `redirectUrl`: it redirects to `https://server.example.org/login/sso/redirect?redirectUrl=https://client.example.com?hs=server.example.org`. diff --git a/content/client-server-api/modules/stickers.md b/content/client-server-api/modules/stickers.md index 32edaacc..0125dd88 100644 --- a/content/client-server-api/modules/stickers.md +++ b/content/client-server-api/modules/stickers.md @@ -16,7 +16,7 @@ when the sticker image is clicked. #### Events Sticker events are received as a single `m.sticker` event in the -`timeline` section of a room, in a `/sync`. +`timeline` section of a room, in a [`/sync`](#get_matrixclientv3sync). {{% event event="m.sticker" %}} diff --git a/content/client-server-api/modules/third_party_invites.md b/content/client-server-api/modules/third_party_invites.md index aff7b530..9ac55f57 100644 --- a/content/client-server-api/modules/third_party_invites.md +++ b/content/client-server-api/modules/third_party_invites.md @@ -5,7 +5,7 @@ This module adds in support for inviting new members to a room where their Matrix user ID is not known, instead addressing them by a third-party identifier such as an email address. There are two flows here; one if a Matrix user ID is known for the third-party identifier, and one if -not. Either way, the client calls `/invite` with the details of the +not. Either way, the client calls [`/invite`](#post_matrixclientv3roomsroomidinvite) with the details of the third-party identifier. The homeserver asks the identity server whether a Matrix user ID is @@ -33,11 +33,11 @@ invitee does indeed own that third-party identifier. See the A client asks a server to invite a user by their third-party identifier. -{{% http-api spec="client-server" api="third_party_membership" %}} +{{% http-api spec="client-server" api="third_party_membership" anchor_base="thirdparty" %}} #### Server behaviour -Upon receipt of an `/invite`, the server is expected to look up the +Upon receipt of an [`/invite`](#post_matrixclientv3roomsroomidinvite), the server is expected to look up the third-party identifier with the provided identity server. If the lookup yields a result for a Matrix User ID then the normal invite process can be initiated. This process ends up looking like this: @@ -186,9 +186,9 @@ residents of the room while H3 is attempting to join. Note that when H1 sends the `m.room.member` event to H2 and H3 it does not have to block on either server's receipt of the event. Likewise, H1 -may complete the `/exchange_third_party_invite/:roomId` request at the +may complete the [`/exchange_third_party_invite`](/server-server-api/#put_matrixfederationv1exchange_third_party_inviteroomid) request at the same time as sending the `m.room.member` event to H2 and H3. -Additionally, H3 may complete the `/3pid/onbind` request it got from IS +Additionally, H3 may complete the [`/3pid/onbind`](/server-server-api/#put_matrixfederationv13pidonbind) request it got from IS at any time - the completion is not shown in the diagram. H1 MUST verify the request from H3 to ensure the `signed` property is diff --git a/content/client-server-api/modules/threading.md b/content/client-server-api/modules/threading.md index 04440a07..5fedbcf8 100644 --- a/content/client-server-api/modules/threading.md +++ b/content/client-server-api/modules/threading.md @@ -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. 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 from an event which itself is the child of an event relationship (i.e., -one with an `m.relates_to` property). It is therefore also not possible to nest -threads. All events in a thread reference the thread root instead of the -most recent message, unlike rich reply chains. +*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 +is the child of an event relationship (i.e., one with an `m.relates_to` +property with a `rel_type` property - see [Relationship types](#relationship-types)). +It is therefore also not possible to nest threads. + +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: @@ -104,10 +106,6 @@ flag to `true`. } ``` -For `m.room.message` events represented this way, no [reply fallback](#fallbacks-for-rich-replies) -is specified. This allows thread-aware clients to discard the `m.in_reply_to` object entirely -when `is_falling_back` is `true`. - {{% boxes/note %}} Clients which are acutely aware of threads (they do not render threads, but are otherwise aware of the feature existing in the spec) can treat rich replies to an event with a `rel_type` diff --git a/content/client-server-api/modules/voip_events.md b/content/client-server-api/modules/voip_events.md index 102e3dcd..14b7d796 100644 --- a/content/client-server-api/modules/voip_events.md +++ b/content/client-server-api/modules/voip_events.md @@ -96,13 +96,8 @@ Matrix clients can send DTMF as specified by WebRTC. The WebRTC standard as of A in the RTP payload. #### Grammar for VoIP IDs -`call_id`s and `party_id` are explicitly defined to be between 1 and 255 characters long, consisting -of the characters `[0-9a-zA-Z._~-]`. -(Note that this matches the grammar of 'opaque IDs' from -[MSC1597](https://github.com/matrix-org/matrix-spec-proposals/blob/rav/proposals/id_grammar/proposals/1597-id-grammar.md#opaque-ids), -and that of the `id` property of the - [`m.login.sso` flow schema](#definition-mloginsso-flow-schema).) +`call_id`s and `party_id` must follow the [Opaque Identifier Grammar](/appendices#opaque-identifiers). #### Behaviour on Room Leave If the client sees the user it is in a call with leave the room, the client should treat this @@ -171,18 +166,35 @@ In response to an incoming invite, a client may do one of several things: ##### Streams -Clients are expected to send one stream with one track of kind `audio` (creating a -voice call). They can optionally send a second track in the same stream of kind -`video` (creating a video call). +Clients may send more than one stream in a VoIP call. The streams should be +differentiated by including metadata in the [`m.call.invite`](/client-server-api/#mcallinvite), +[`m.call.answer`](/client-server-api/#mcallanswer) and [`m.call.negotiate`](/client-server-api/#mcallnegotiate) +events, using the `sdp_stream_metadata` property. An [`m.call.sdp_stream_metadata_changed`](/client-server-api/#mcallsdp_stream_metadata_changed) +event can be sent when the metadata changes but no negotiation is required. -Clients implementing this specification use the first stream and will ignore -any streamless tracks. Note that in the JavaScript WebRTC API, this means -`addTrack()` must be passed two parameters: a track and a stream, not just a -track, and in a video call the stream must be the same for both audio and video -track. +Clients are recommended to not mute the audio of WebRTC tracks locally when an +incoming stream has the `audio_muted` field set to `true`. This is because when +the other user unmutes themselves, there may be a slight delay between their +client sending audio and the [`m.call.sdp_stream_metadata_changed`](/client-server-api/#mcallsdp_stream_metadata_changed) +event arriving and any audio sent in between will not be heard. The other user +will still stop transmitting audio once they mute on their side, so no audio is +sent without the user's knowledge. -A client may send other streams and tracks but the behaviour of the other party -with respect to presenting such streams and tracks is undefined. +The same suggestion does not apply to `video_muted`. Clients _should_ mute video +locally, so that the receiving side doesn't see a black video. + +If `sdp_stream_metadata` is present and an incoming stream is not listed in it, +the stream should be ignored. If a stream has a `purpose` of an unknown type, it +should also be ignored. + +For backwards compatibility, if `sdp_stream_metadata` is not present in the +initial [`m.call.invite`](/client-server-api/#mcallinvite) or [`m.call.answer`](/client-server-api/#mcallanswer) +event sent by the other party, the client should assume that this property is +not supported by the other party. It means that multiple streams cannot be +differentiated: the client should only use the first incoming stream and +shouldn't send more than one stream. + +Clients implementing this specification should ignore any streamless tracks. ##### Invitees The `invitee` field should be added whenever the call is intended for one diff --git a/content/identity-service-api.md b/content/identity-service-api.md index 9e2d5cdf..3c20a12a 100644 --- a/content/identity-service-api.md +++ b/content/identity-service-api.md @@ -162,15 +162,20 @@ of access tokens to authenticate users. The access tokens provided by an Identity Server cannot be used to authenticate Client-Server API requests. -An access token is provided to an endpoint in one of two ways: +Access tokens may be provided via a request header, using the +Authentication Bearer scheme: `Authorization: Bearer TheTokenHere`. -1. Via a query string parameter, `access_token=TheTokenHere`. -2. Via a request header, `Authorization: Bearer TheTokenHere`. +Clients may alternatively provide the access token via a query string +parameter: `access_token=TheTokenHere`. This method is deprecated to +prevent the access token being leaked in access/HTTP logs and SHOULD NOT +be used by clients. -Clients are encouraged to the use the `Authorization` header where -possible to prevent the access token being leaked in access/HTTP logs. -The query string should only be used in cases where the `Authorization` -header is inaccessible for the client. +Identity Servers MUST support both methods. + +{{% boxes/note %}} +{{% changed-in v="1.11" %}} +Sending the access token as a query string parameter is now deprecated. +{{% /boxes/note %}} When credentials are required but missing or invalid, the HTTP call will return with a status of 401 and the error code `M_UNAUTHORIZED`. diff --git a/content/proposals.md b/content/proposals.md index dac520c9..b58a98be 100644 --- a/content/proposals.md +++ b/content/proposals.md @@ -380,9 +380,18 @@ As part of the proposal process the Spec Core Team will require evidence of the MSC working in order for it to move into FCP. This can usually be a branch/pull request to whichever implementation of choice that proves the MSC works in practice, though in some cases the MSC itself will be -small enough to be considered proven. Where it's unclear if an MSC will -require an implementation proof, ask in -[\#matrix-spec:matrix.org](https://matrix.to/#/#matrix-spec:matrix.org). +small enough to be considered proven. Implementations do not need to be +merged or released, but must be of sufficient quality to show that the +MSC works. Where it's unclear if an MSC will require an implementation +proof, ask in [\#matrix-spec:matrix.org](https://matrix.to/#/#matrix-spec:matrix.org). +Proposals may require both server-side and client-side implementations. + +Proposals that have not yet been implemented will have the +`needs-implementation` label. After an implementation has been made, add a +comment in the GitHub issue indicating so. After an implementation has been +made, we will check it to verify that it implements the MSC. Proposals that +have implementations that have not yet been checked will have the +`implementation-needs-checking` label. ### Early release of an MSC/idea diff --git a/content/rooms/_index.md b/content/rooms/_index.md index e75fbb13..9334c3a1 100644 --- a/content/rooms/_index.md +++ b/content/rooms/_index.md @@ -36,11 +36,11 @@ Alternatively, consider flipping the column/row organization to be features up top and versions on the left. --> -| Feature \ Version | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -|-------------------|---|---|---|---|---|---|---|---|---|----| -| **Knocking** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | -| **Restricted join rules** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | -| **`knock_restricted` join rule** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | +| Feature \ Version | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | +|-------------------|---|---|---|---|---|---|---|---|---|----|----| +| **Knocking** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | +| **Restricted join rules** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | +| **`knock_restricted` join rule** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ## Complete list of room versions @@ -57,8 +57,7 @@ the default room version when creating new rooms. The available room versions are: -- [Version 1](/rooms/v1) - **Stable**. The current version of most - rooms. +- [Version 1](/rooms/v1) - **Stable**. The initial room version. - [Version 2](/rooms/v2) - **Stable**. Implements State Resolution Version 2. - [Version 3](/rooms/v3) - **Stable**. Introduces events whose IDs @@ -76,6 +75,7 @@ The available room versions are: redacting some membership events. - [Version 10](/rooms/v10) - **Stable**. Enforces integer-only power levels and adds `knock_restricted` join rule. +- [Version 11](/rooms/v11) - **Stable**. Clarifies the redaction algorithm. ## Room version grammar diff --git a/content/rooms/fragments/v1-redactions.md b/content/rooms/fragments/v1-redactions.md index f38c85f3..4731dbab 100644 --- a/content/rooms/fragments/v1-redactions.md +++ b/content/rooms/fragments/v1-redactions.md @@ -19,12 +19,14 @@ not in the following list: - `membership` 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.create` allows key `creator`. -- `m.room.join_rules` allows key `join_rule`. -- `m.room.power_levels` allows keys `ban`, `events`, `events_default`, - `kick`, `redact`, `state_default`, `users`, `users_default`. -- `m.room.aliases` allows key `aliases`. -- `m.room.history_visibility` allows key `history_visibility`. +- [`m.room.member`](/client-server-api#mroommember) allows key `membership`. +- [`m.room.create`](/client-server-api#mroomcreate) allows key `creator`. +- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) allows key `join_rule`. +- [`m.room.power_levels`](/client-server-api#mroompower_levels) allows keys + `ban`, `events`, `events_default`, `kick`, `redact`, `state_default`, `users`, + `users_default`. +- [`m.room.aliases`](/client-server-api#historical-events) allows key `aliases`. +- [`m.room.history_visibility`](/client-server-api#mroomhistory_visibility) allows + key `history_visibility`. diff --git a/content/rooms/fragments/v11-event-format.md b/content/rooms/fragments/v11-event-format.md new file mode 100644 index 00000000..a4da710d --- /dev/null +++ b/content/rooms/fragments/v11-event-format.md @@ -0,0 +1,4 @@ + +Events in rooms of this version have the following structure: + +{{% definition path="api/server-server/definitions/pdu_v11" %}} diff --git a/content/rooms/fragments/v11-redactions.md b/content/rooms/fragments/v11-redactions.md new file mode 100644 index 00000000..3bde94ba --- /dev/null +++ b/content/rooms/fragments/v11-redactions.md @@ -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`. \ No newline at end of file diff --git a/content/rooms/fragments/v2-state-res.md b/content/rooms/fragments/v2-state-res.md index 731070a7..725cd08f 100644 --- a/content/rooms/fragments/v2-state-res.md +++ b/content/rooms/fragments/v2-state-res.md @@ -50,7 +50,7 @@ chain for each state *S**i*, that is the union of the auth chains for each event in *S**i*, and then taking every event that doesn't appear in every auth chain. If *C**i* is the full auth chain of *S**i*, then the auth difference is - ∪ *C**i* −  ∩ *C**i*. +∪ *C**i* − ∩ *C**i*. **Full conflicted set.** The *full conflicted set* is the union of the conflicted state set and @@ -138,7 +138,7 @@ The *resolution* of a set of states is obtained as follows: 1. Select the set *X* of all *power events* that appear in the *full conflicted set*. For each such power event *P*, enlarge *X* by adding the events in the auth chain of *P* which also belong to the full - conflicted set. Sort $X$ into a list using the *reverse topological + conflicted set. Sort *X* into a list using the *reverse topological power ordering*. 2. Apply the *iterative auth checks algorithm*, starting from the *unconflicted state map*, to the list of events from the previous diff --git a/content/rooms/fragments/v3-auth-rules.md b/content/rooms/fragments/v3-auth-rules.md index 05b8065a..aec33743 100644 --- a/content/rooms/fragments/v3-auth-rules.md +++ b/content/rooms/fragments/v3-auth-rules.md @@ -1,6 +1,6 @@ --- --- -{{< added-in this=true >}} In room versions 1 and 2, events need a +{{% added-in v=3 %}} In room versions 1 and 2, events need a signature from the domain of the `event_id` in order to be considered valid. This room version does not include an `event_id` over federation in the same respect, so does not need a signature from that server. diff --git a/content/rooms/fragments/v3-handling-redactions.md b/content/rooms/fragments/v3-handling-redactions.md index 5a9aa7c6..80d478bf 100644 --- a/content/rooms/fragments/v3-handling-redactions.md +++ b/content/rooms/fragments/v3-handling-redactions.md @@ -1,6 +1,6 @@ --- --- -{{% added-in this=true %}} In room versions 1 and 2, redactions were +{{% added-in v=3 %}} In room versions 1 and 2, redactions were explicitly part of the [authorization rules](/rooms/v1/#authorization-rules) under Rule 11. As of room version 3, these conditions no longer exist as represented by [this version's authorization rules](#authorization-rules). diff --git a/content/rooms/fragments/v4-event-ids.md b/content/rooms/fragments/v4-event-ids.md index 804d97ec..d6ad398f 100644 --- a/content/rooms/fragments/v4-event-ids.md +++ b/content/rooms/fragments/v4-event-ids.md @@ -1,6 +1,6 @@ --- --- -{{% added-in this=true %}} The event ID is the [reference +{{% added-in v=4 %}} The event ID is the [reference hash](/server-server-api#calculating-the-reference-hash-for-an-event) of the event encoded using a variation of [Unpadded Base64](/appendices#unpadded-base64) which replaces the 62nd and diff --git a/content/rooms/fragments/v6-redactions.md b/content/rooms/fragments/v6-redactions.md index 71ecf854..47b024a2 100644 --- a/content/rooms/fragments/v6-redactions.md +++ b/content/rooms/fragments/v6-redactions.md @@ -19,11 +19,13 @@ not in the following list: - `membership` 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.create` allows key `creator`. -- `m.room.join_rules` allows key `join_rule`. -- `m.room.power_levels` allows keys `ban`, `events`, `events_default`, - `kick`, `redact`, `state_default`, `users`, `users_default`. -- `m.room.history_visibility` allows key `history_visibility`. +- [`m.room.member`](/client-server-api#mroommember) allows key `membership`. +- [`m.room.create`](/client-server-api#mroomcreate) allows key `creator`. +- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) allows key `join_rule`. +- [`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`. diff --git a/content/rooms/fragments/v8-auth-rules.md b/content/rooms/fragments/v8-auth-rules.md index 98a88bf1..8da010ef 100644 --- a/content/rooms/fragments/v8-auth-rules.md +++ b/content/rooms/fragments/v8-auth-rules.md @@ -1,12 +1,6 @@ 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) @@ -21,6 +15,18 @@ For example, mentions of the `sender`'s power level can also refer to the default power level for users in the room. {{% /boxes/note %}} +{{% boxes/note %}} +`m.room.redaction` events are subject to auth rules in the same way as any other event. +In practice, that means they will normally be allowed by the auth rules, unless the +`m.room.power_levels` event sets a power level requirement for `m.room.redaction` +events via the `events` or `events_default` properties. In particular, the _redact +level_ is **not** considered by the auth rules. + +The ability to send a redaction event does not mean that the redaction itself should +be performed. Receiving servers must perform additional checks, as described in +the [Handling Redactions](#handling-redactions) section. +{{% /boxes/note %}} + The rules are as follows: 1. If type is `m.room.create`: @@ -48,7 +54,7 @@ The rules are as follows: 4. If type is `m.room.member`: 1. If there is no `state_key` property, or no `membership` property in `content`, reject. - 2. {{< added-in this=true >}} + 2. {{% added-in v=8 %}} If `content` has a `join_authorised_via_users_server` property: 1. If the event is not validly signed by the homeserver of the user ID denoted by the key, reject. @@ -59,7 +65,7 @@ The rules are as follows: 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. {{< added-in this=true >}} + 5. {{% added-in v=8 %}} If the `join_rule` is `restricted`: 1. If membership state is `join` or `invite`, allow. 2. If the `join_authorised_via_users_server` key in `content` @@ -117,7 +123,8 @@ The rules are as follows: 7. If `membership` is `knock`: 1. If the `join_rule` is anything other than `knock`, 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. 8. Otherwise, the membership is unknown. Reject. 5. If the `sender`'s current membership state is not `join`, reject. diff --git a/content/rooms/fragments/v9-redactions.md b/content/rooms/fragments/v9-redactions.md index 18c100a5..27cd97f0 100644 --- a/content/rooms/fragments/v9-redactions.md +++ b/content/rooms/fragments/v9-redactions.md @@ -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 not in the following list: @@ -40,11 +19,15 @@ not in the following list: - `membership` 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.create` allows key `creator`. -- `m.room.join_rules` allows keys `join_rule`, `allow`. -- `m.room.power_levels` allows keys `ban`, `events`, `events_default`, - `kick`, `redact`, `state_default`, `users`, `users_default`. -- `m.room.history_visibility` allows key `history_visibility`. \ No newline at end of file +- [`m.room.member`](/client-server-api#mroommember) allows keys `membership`, + `join_authorised_via_users_server`. +- [`m.room.create`](/client-server-api#mroomcreate) allows key `creator`. +- [`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`, `kick`, `redact`, `state_default`, `users`, + `users_default`. +- [`m.room.history_visibility`](/client-server-api#mroomhistory_visibility) + allows key `history_visibility`. \ No newline at end of file diff --git a/content/rooms/v1.md b/content/rooms/v1.md index 04055e8c..1b950f11 100644 --- a/content/rooms/v1.md +++ b/content/rooms/v1.md @@ -2,6 +2,7 @@ title: Room Version 1 type: docs weight: 10 +version: 1 --- This room version is the first ever version for rooms, and contains the diff --git a/content/rooms/v10.md b/content/rooms/v10.md index 46bdb4c7..974a0822 100644 --- a/content/rooms/v10.md +++ b/content/rooms/v10.md @@ -2,6 +2,7 @@ title: Room Version 10 type: docs weight: 100 +version: 10 --- This room version builds on [version 9](/rooms/v9) to enforce that power level @@ -76,12 +77,6 @@ correctly structured are rejected under the authorization rules below. 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) @@ -96,6 +91,18 @@ For example, mentions of the `sender`'s power level can also refer to the default power level for users in the room. {{% /boxes/note %}} +{{% boxes/note %}} +`m.room.redaction` events are subject to auth rules in the same way as any other event. +In practice, that means they will normally be allowed by the auth rules, unless the +`m.room.power_levels` event sets a power level requirement for `m.room.redaction` +events via the `events` or `events_default` properties. In particular, the _redact +level_ is **not** considered by the auth rules. + +The ability to send a redaction event does not mean that the redaction itself should +be performed. Receiving servers must perform additional checks, as described in +the [Handling redactions](#handling-redactions) section. +{{% /boxes/note %}} + The rules are as follows: 1. If type is `m.room.create`: @@ -134,7 +141,7 @@ The rules are as follows: 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. {{< changed-in this="true" >}} + 5. {{% changed-in v=10 %}} 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` @@ -190,11 +197,12 @@ The rules are as follows: than the `sender`'s power level, allow. 3. Otherwise, reject. 7. If `membership` is `knock`: - 1. {{< changed-in this="true" >}} + 1. {{% changed-in v=10 %}} 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` or `join`, allow. + 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. @@ -206,15 +214,15 @@ The rules are as follows: 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. {{< added-in this="true" >}} + 1. {{% added-in v=10 %}} 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. {{< added-in this="true" >}} + 2. {{% added-in v=10 %}} 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 + 3. If the `users` property in `content` is not an object with keys that are valid user IDs with values that are integers, reject. 4. If there is no previous `m.room.power_levels` event in the room, allow. diff --git a/content/rooms/v11.md b/content/rooms/v11.md new file mode 100644 index 00000000..1be3a405 --- /dev/null +++ b/content/rooms/v11.md @@ -0,0 +1,292 @@ +--- +title: Room Version 11 +type: docs +weight: 100 +version: 11 +--- + +This room version builds on [version 10](/rooms/v10) while clarifying redaction +rules. + +## Client considerations + +### Redactions + +{{% added-in v=11 %}} 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" %}} + +### 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 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. + +The types of state events that affect authorization are: + +- [`m.room.create`](/client-server-api#mroomcreate) +- [`m.room.member`](/client-server-api#mroommember) +- [`m.room.join_rules`](/client-server-api#mroomjoin_rules) +- [`m.room.power_levels`](/client-server-api#mroompower_levels) +- [`m.room.third_party_invite`](/client-server-api#mroomthird_party_invite) + +{{% boxes/note %}} +Power levels are inferred from defaults when not explicitly supplied. +For example, mentions of the `sender`'s power level can also refer to +the default power level for users in the room. +{{% /boxes/note %}} + +{{% boxes/note %}} +`m.room.redaction` events are subject to auth rules in the same way as any other event. +In practice, that means they will normally be allowed by the auth rules, unless the +`m.room.power_levels` event sets a power level requirement for `m.room.redaction` +events via the `events` or `events_default` properties. In particular, the _redact +level_ is **not** considered by the auth rules. + +The ability to send a redaction event does not mean that the redaction itself should +be performed. Receiving servers must perform additional checks, as described in +the [Handling redactions](#handling-redactions) section. +{{% /boxes/note %}} + +The rules are as follows: + +1. {{% changed-in v=11 %}} + 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 v=11 %}} + If the only previous event is an `m.room.create` and the + `state_key` is the sender of the `m.room.create`, allow. + 2. If the `sender` does not match `state_key`, reject. + 3. If the `sender` is banned, reject. + 4. If the `join_rule` is `invite` or `knock` then allow if + membership state is `invite` or `join`. + 5. If the `join_rule` is `restricted` or `knock_restricted`: + 1. If membership state is `join` or `invite`, allow. + 2. If the `join_authorised_via_users_server` key in `content` + is not a user with sufficient permission to invite other + users, 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 object 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" %}} diff --git a/content/rooms/v2.md b/content/rooms/v2.md index 097f2554..f9980261 100644 --- a/content/rooms/v2.md +++ b/content/rooms/v2.md @@ -2,6 +2,7 @@ title: Room Version 2 type: docs weight: 20 +version: 2 --- This room version builds on [version 1](/rooms/v1) with an improved @@ -27,7 +28,7 @@ changing only the state resolution algorithm. ### State resolution -{{% added-in this=true %}} +{{% added-in v=2 %}} {{% rver-fragment name="v2-state-res" %}} diff --git a/content/rooms/v3.md b/content/rooms/v3.md index dd2fd144..6a3522b7 100644 --- a/content/rooms/v3.md +++ b/content/rooms/v3.md @@ -2,6 +2,7 @@ title: Room Version 3 type: docs weight: 30 +version: 3 --- This room version builds on [version 2](/rooms/v2) with an improved event @@ -39,8 +40,7 @@ all the remaining behaviour described by [room version 2](/rooms/v2). ### Handling redactions - -{{% rver-fragment name="v3-handling-redactions" withVersioning=true %}} +{{% rver-fragment name="v3-handling-redactions" %}} ### Event IDs @@ -54,7 +54,7 @@ the use of a dedicated event ID, servers are required to track the hashes on an event to determine its ID. {{% /boxes/rationale %}} -{{% added-in this=true %}} The event ID is the [reference +{{% added-in v=3 %}} The event ID is the [reference hash](/server-server-api#calculating-the-reference-hash-for-an-event) of the event encoded using [Unpadded Base64](/appendices#unpadded-base64), prefixed with `$`. A @@ -89,15 +89,19 @@ The complete structure of a event in a v3 room is shown below. ### Authorization rules -{{< added-in this=true >}} `m.room.redaction` events are no longer -explicitly part of the auth rules. They are still subject to the -minimum power level rules, but should always fall into "11. Otherwise, -allow". Instead of being authorized at the time of receipt, they are -authorized at a later stage: see the [Handling Redactions](#handling-redactions) -section below for more information. +{{% boxes/note %}} +{{% added-in v=3 %}} `m.room.redaction` events are subject to auth rules in +the same way as any other event. In practice, that means they will normally be allowed +by the auth rules, unless the `m.room.power_levels` event sets a power level requirement +for `m.room.redaction`events via the `events` or `events_default` properties. In +particular, the _redact level_ is **not** considered by the auth rules. - -{{< rver-fragment name="v3-auth-rules" withVersioning=true >}} +The ability to send a redaction event does not mean that the redaction itself should +be performed. Receiving servers must perform additional checks, as described in +the [Handling Redactions](#handling-redactions) section. +{{% /boxes/note %}} + +{{% rver-fragment name="v3-auth-rules" %}} ## Unchanged from v2 diff --git a/content/rooms/v4.md b/content/rooms/v4.md index c329f342..bd5651e1 100644 --- a/content/rooms/v4.md +++ b/content/rooms/v4.md @@ -2,6 +2,7 @@ title: Room Version 4 type: docs weight: 40 +version: 4 --- This room version builds on [version 3](/rooms/v3) using a different @@ -46,7 +47,7 @@ being interpreted differently by some reverse proxy software, and generally made administration harder. {{% /boxes/rationale %}} -{{% rver-fragment name="v4-event-ids" withVersioning="true" %}} +{{% rver-fragment name="v4-event-ids" %}} ## Unchanged from v3 diff --git a/content/rooms/v5.md b/content/rooms/v5.md index 25147e9e..665b0568 100644 --- a/content/rooms/v5.md +++ b/content/rooms/v5.md @@ -2,6 +2,7 @@ title: Room Version 5 type: docs weight: 50 +version: 5 --- This room version builds on [version 4](/rooms/v4) while enforcing signing diff --git a/content/rooms/v6.md b/content/rooms/v6.md index 977f5479..b2a5f024 100644 --- a/content/rooms/v6.md +++ b/content/rooms/v6.md @@ -2,6 +2,7 @@ title: Room Version 6 type: docs weight: 60 +version: 6 --- This room version builds on [version 5](/rooms/v5) while changing various @@ -15,7 +16,7 @@ which implement the redaction algorithm locally should refer to the ### Redactions -{{% added-in this=true %}} All significant meaning for `m.room.aliases` +{{% added-in v=6 %}} All significant meaning for `m.room.aliases` has been removed from the redaction algorithm. The remaining rules are the same as past room versions. @@ -40,17 +41,11 @@ in [room version 5](/rooms/v5). ### Authorization rules -`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 -[Handling Redactions](#handling-redactions) section below for more information. - -{{< added-in this=true >}} Rule 4, which related specifically to events +{{% added-in v=6 %}} Rule 4, which related specifically to events of type `m.room.aliases`, is removed. `m.room.aliases` events must still pass authorization checks relating to state events. -{{< added-in this=true >}} Additionally, the authorization rules for events of +{{% added-in v=6 %}} Additionally, the authorization rules for events of type `m.room.power_levels` now include a `notifications` property under `content`. This updates rules 10.4 and 10.5 (now 9.4 and 9.5), which checked the `events` property. @@ -71,6 +66,18 @@ For example, mentions of the `sender`'s power level can also refer to the default power level for users in the room. {{% /boxes/note %}} +{{% boxes/note %}} +`m.room.redaction` events are subject to auth rules in the same way as any other event. +In practice, that means they will normally be allowed by the auth rules, unless the +`m.room.power_levels` event sets a power level requirement for `m.room.redaction` +events via the `events` or `events_default` properties. In particular, the _redact +level_ is **not** considered by the auth rules. + +The ability to send a redaction event does not mean that the redaction itself should +be performed. Receiving servers must perform additional checks, as described in +the [Handling Redactions](#handling-redactions) section. +{{% /boxes/note %}} + The rules are as follows: 1. If type is `m.room.create`: @@ -168,12 +175,12 @@ The rules are as follows: power level, reject. 2. If the new value is higher than the `sender`'s current power level, reject. - 4. {{< changed-in this="true" >}} + 4. {{% changed-in v=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. - 5. {{< changed-in this="true" >}} + 5. {{% changed-in v=6 %}} 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 diff --git a/content/rooms/v7.md b/content/rooms/v7.md index 40a9962c..216646d3 100644 --- a/content/rooms/v7.md +++ b/content/rooms/v7.md @@ -2,6 +2,7 @@ title: Room Version 7 type: docs weight: 70 +version: 7 --- This room version builds on [version 6](/rooms/v6) to introduce knocking @@ -32,17 +33,11 @@ as do the versions v6 is based upon. ### Authorization rules -{{< added-in this=true >}} For checks performed upon `m.room.member` events, a +{{% added-in v=7 %}} For checks performed upon `m.room.member` events, a new point for `membership=knock` is added. 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) @@ -57,6 +52,18 @@ For example, mentions of the `sender`'s power level can also refer to the default power level for users in the room. {{% /boxes/note %}} +{{% boxes/note %}} +`m.room.redaction` events are subject to auth rules in the same way as any other event. +In practice, that means they will normally be allowed by the auth rules, unless the +`m.room.power_levels` event sets a power level requirement for `m.room.redaction` +events via the `events` or `events_default` properties. In particular, the _redact +level_ is **not** considered by the auth rules. + +The ability to send a redaction event does not mean that the redaction itself should +be performed. Receiving servers must perform additional checks, as described in +the [Handling redactions](#handling-redactions) section. +{{% /boxes/note %}} + The rules are as follows: 1. If type is `m.room.create`: @@ -83,7 +90,7 @@ The rules are as follows: `state_key` is the creator, allow. 2. If the `sender` does not match `state_key`, reject. 3. If the `sender` is banned, reject. - 4. {{< changed-in this=true >}} + 4. {{% changed-in v=7 %}} If the `join_rule` is `invite` or `knock` then allow if membership state is `invite` or `join`. 5. If the `join_rule` is `public`, allow. @@ -115,7 +122,7 @@ The rules are as follows: the *invite level*, allow. 5. Otherwise, reject. 4. If `membership` is `leave`: - 1. {{< changed-in this=true >}} + 1. {{% changed-in v=7 %}} If the `sender` matches `state_key`, allow if and only if that user's current membership state is `invite`, `join`, or `knock`. @@ -135,11 +142,12 @@ The rules are as follows: the *ban level*, and the *target user*'s power level is less than the `sender`'s power level, allow. 3. Otherwise, reject. - 6. {{< added-in this=true >}} + 6. {{% added-in v=7 %}} If `membership` is `knock`: 1. If the `join_rule` is anything other than `knock`, 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. 7. Otherwise, the membership is unknown. Reject. 5. If the `sender`'s current membership state is not `join`, reject. diff --git a/content/rooms/v8.md b/content/rooms/v8.md index ab4cd970..c6c116a8 100644 --- a/content/rooms/v8.md +++ b/content/rooms/v8.md @@ -2,6 +2,7 @@ title: Room Version 8 type: docs weight: 80 +version: 8 --- This room version builds on [version 7](/rooms/v7) to introduce a new @@ -27,7 +28,7 @@ Clients which implement the redaction algorithm locally should refer to the ### Redactions -{{% added-in this=true %}} `m.room.join_rules` events now keep `allow` in addition to other +{{% added-in v=8 %}} `m.room.join_rules` events now keep `allow` in addition to other keys in `content` when being redacted. {{% boxes/warning %}} @@ -83,11 +84,11 @@ room without invite. Otherwise, the room version inherits all properties of ### Authorization rules -{{< added-in this=true >}} For checks performed upon `m.room.member` events, new +{{% added-in v=8 %}} For checks performed upon `m.room.member` events, new points for handling `content.join_authorised_via_users_server` are added (Rule 4.2 and 4.3.5). -{{< rver-fragment name="v8-auth-rules" withVersioning=true >}} +{{% rver-fragment name="v8-auth-rules" %}} ### Redactions diff --git a/content/rooms/v9.md b/content/rooms/v9.md index f6735415..582ff6b4 100644 --- a/content/rooms/v9.md +++ b/content/rooms/v9.md @@ -2,6 +2,7 @@ title: Room Version 9 type: docs weight: 90 +version: 9 --- This room version builds on [version 8](/rooms/v8) to add additional redaction @@ -17,7 +18,28 @@ Clients which implement the redaction algorithm locally should refer to the ### Redactions -{{% rver-fragment name="v9-redactions" withVersioning="true" %}} +{{% added-in v=9 %}} [`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" %}} ## Server implementation components @@ -62,7 +84,7 @@ completeness. ### Authorization rules -{{< rver-fragment name="v8-auth-rules" >}} +{{% rver-fragment name="v8-auth-rules" %}} ### State resolution diff --git a/content/server-server-api.md b/content/server-server-api.md index 2dc80da5..8e99c431 100644 --- a/content/server-server-api.md +++ b/content/server-server-api.md @@ -110,7 +110,7 @@ to send. The process overall is as follows: given. The target server must present a valid certificate for the IP address. The `Host` header in the request should be set to the server name, including the port if the server name included one. - + 2. If the hostname is not an IP literal, and the server name includes an explicit port, resolve the hostname to an IP address using CNAME, AAAA or A records. @@ -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 parsed as `[:]` and processed as follows: - - If `` is an IP literal, then that IP address + 1. If `` is an IP literal, then that IP address should be used together with the `` or 8448 if no port is provided. The target server must present a valid TLS certificate for the IP address. Requests must be made with a `Host` header containing the IP address, including the port if one was provided. - - If `` is not an IP literal, and + 2. If `` is not an IP literal, and `` is present, an IP address is discovered by looking up CNAME, AAAA or A records for ``. The resulting IP address is used, alongside the ``. Requests must be made with a `Host` header of `:`. The target server must present a valid certificate for ``. - - If `` is not an IP literal and no + 3. {{% added-in v="1.8" %}} If `` is not an IP literal and no `` is present, an SRV record is looked up for + `_matrix-fed._tcp.`. 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 ``. The + target server must present a valid certificate for + ``. + 4. **[Deprecated]** If `` is not an IP literal, no + `` is present, and a `_matrix-fed._tcp.` + SRV record was not found, an SRV record is looked up for `_matrix._tcp.`. 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 ``. The target server must present a valid certificate for ``. - - 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 + 5. If no SRV record is found, an IP address is resolved using CNAME, AAAA + or A records. Requests are then made to the resolved IP address and a port of 8448, using a `Host` header of ``. The target server must present a valid certificate for ``. -4. If the `/.well-known` request resulted in an error response, a - server is found by resolving an SRV record for - `_matrix._tcp.`. 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, using 8448 as a default port, with a - `Host` header of ``. The target server must present a - valid certificate for ``. +4. {{% added-in v="1.8" %}} If the `/.well-known` request resulted in an error response, a server is + found by resolving an SRV record for `_matrix-fed._tcp.`. 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 ``. The target server must present a valid certificate + for ``. -5. If the `/.well-known` request returned an error response, and the - SRV record was not found, an IP address is resolved using CNAME, AAAA and A +5. **[Deprecated]** If the `/.well-known` request resulted in an error response, + and a `_matrix-fed._tcp.` SRV record was not found, a server is + found by resolving an SRV record for `_matrix._tcp.`. 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 ``. The target server must present a valid certificate + for ``. + +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 8448 and a `Host` header containing the ``. The target server must present a valid certificate for ``. @@ -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) {{% /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" %}} ### Server implementation @@ -266,7 +290,7 @@ Step 1 sign JSON: ``` { - "method": "GET", + "method": "POST", "uri": "/target", "origin": "origin.hs.example.com", "destination": "destination.hs.example.com", @@ -287,7 +311,7 @@ condition applies throughout the request signing process. 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..." Content-Type: application/json @@ -325,13 +349,14 @@ def authorization_headers(origin_name, origin_signing_key, ``` The format of the Authorization header is given in -[RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-2.1). In -summary, the header begins with authorization scheme `X-Matrix`, followed by -one or more spaces, followed by a comma-separated list of parameters written as -name=value pairs. The names are case insensitive and order does not matter. The +[Section 11.4 of RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#section-11.4). In +summary, the header begins with authorization scheme `X-Matrix`, followed by one +or more spaces, followed by a comma-separated list of parameters written as +name=value pairs. Zero or more spaces and tabs around each comma are allowed. +The names are case insensitive and order does not matter. The values must be enclosed in quotes if they contain characters that are not allowed in `token`s, as defined in -[RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6); if a +[Section 5.6.2 of RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#section-5.6.2); if a value is a valid `token`, it may or may not be enclosed in quotes. Quoted values may include backslash-escaped characters. When parsing the header, the recipient must unescape the characters. That is, a backslash-character pair is @@ -339,8 +364,9 @@ replaced by the character that follows the backslash. For compatibility with older servers, the sender should - only include one space after `X-Matrix`, -- only use lower-case names, and -- avoid using backslashes in parameter values. +- only use lower-case names, +- avoid using backslashes in parameter values, and +- avoid including whitespace around the commas between name=value pairs. For compatibility with older servers, the recipient should allow colons to be included in values without requiring the value to be enclosed in quotes. @@ -349,7 +375,7 @@ The authorization parameters to include are: - `origin`: the server name of the sending server. This is the same as the `origin` field from JSON described in step 1. -- `destination`: {{< added-in v="1.3" >}} the server name of the receiving +- `destination`: {{% added-in v="1.3" %}} the server name of the receiving server. This is the same as the `destination` field from the JSON described in step 1. For compatibility with older servers, recipients should accept requests without this parameter, but MUST always send it. If this property @@ -362,6 +388,13 @@ The authorization parameters to include are: Unknown parameters are ignored. +{{% boxes/note %}} +{{% changed-in v="1.11" %}} +This section used to reference [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-2.1) +and [RFC 7230](https://datatracker.ietf.org/doc/html/rfc9110#section-5.6.2), that +were obsoleted by RFC 9110 without changes to the sections of interest here. +{{% /boxes/note %}} + ### Response Authentication Responses are authenticated by the TLS server certificate. A homeserver @@ -1163,15 +1196,24 @@ using the following EDU: Attachments to events (images, files, etc) are uploaded to a homeserver via the Content Repository described in the [Client-Server -API](/client-server-api). When a server wishes +API](/client-server-api/#content-repository). When a server wishes to serve content originating from a remote server, it needs to ask the remote server for the media. -Servers should use the server described in the Matrix Content URI, which -has the format `mxc://{ServerName}/{MediaID}`. Servers should use the -download endpoint described in the [Client-Server -API](/client-server-api), being sure to use -the `allow_remote` parameter (set to `false`). +Servers MUST use the server described in the [Matrix Content URI](/client-server-api/#matrix-content-mxc-uris). +Formatted as `mxc://{ServerName}/{MediaID}`, servers MUST download the media from +`ServerName` using the below endpoints. + +{{% changed-in v="1.11" %}} Servers were previously advised to use the `/_matrix/media/*` +endpoints described by the [Content Repository module in the Client-Server API](/client-server-api/#content-repository), +however, those endpoints have been deprecated. New endpoints are introduced which +require authentication. Naturally, as a server is not a user, they cannot provide +the required access token to those endpoints. Instead, servers MUST try the endpoints +described below before falling back to the deprecated `/_matrix/media/*` endpoints +when they receive a `404 M_UNRECOGNIZED` error. When falling back, servers MUST +be sure to set `allow_remote` to `false`. + +{{% http-api spec="server-server" api="content_repository" %}} ## Server Access Control Lists (ACLs) @@ -1186,7 +1228,6 @@ of `M_FORBIDDEN`. The following endpoint prefixes MUST be protected: -- `/_matrix/federation/v1/send` (on a per-PDU basis) - `/_matrix/federation/v1/make_join` - `/_matrix/federation/v1/make_leave` - `/_matrix/federation/v1/send_join` @@ -1203,6 +1244,22 @@ The following endpoint prefixes MUST be protected: - `/_matrix/federation/v1/event_auth` - `/_matrix/federation/v1/get_missing_events` +Additionally the [`/_matrix/federation/v1/send/{txnId}`](#put_matrixfederationv1sendtxnid) +endpoint MUST be protected as follows: + +- ACLs MUST be applied to all PDUs on a per-PDU basis. If the sending + server is denied access to the room identified by `room_id`, the PDU + MUST be ignored with an appropriate error included in the response + for the respective event ID. +- ACLs MUST be applied to all EDUs that are local to a specific room: + + - For [typing notifications (`m.typing`)](#typing-notifications), if + the sending server is denied access to the room identified by + `room_id`, the EDU MUST be ignored. + - For [receipts (`m.receipt`)](#receipts), all receipts for a particular + room ID MUST be ignored if the sending server is denied access to + the room identified by that ID. + ## Signing Events Signing events is complicated by the fact that servers can choose to diff --git a/data-definitions/sas-emoji-v1-i18n/ar.json b/data-definitions/sas-emoji-v1-i18n/ar.json index 822d6f1c..5935ffd6 100644 --- a/data-definitions/sas-emoji-v1-i18n/ar.json +++ b/data-definitions/sas-emoji-v1-i18n/ar.json @@ -50,17 +50,17 @@ "Flower": "زَهرَة", "Butterfly": "فَرَاشَة", "Octopus": "أُخطُبُوط", - "Fish": "سَمَكَة", + "Fish": "سَمَكة", "Turtle": "سُلحفاة", - "Penguin": "بِطريق", + "Penguin": "بطريق", "Rooster": "دِيك", "Panda": "باندَا", "Rabbit": "أَرنَب", "Elephant": "فِيل", "Pig": "خِنزِير", - "Unicorn": "حِصَانٌ بِقَرن", + "Unicorn": "حصان وحيد القرن", "Horse": "حِصَان", "Lion": "أَسَد", "Cat": "هِرَّة", - "Dog": "كَلب" + "Dog": "كلب" } diff --git a/data-definitions/sas-emoji-v1-i18n/cs.json b/data-definitions/sas-emoji-v1-i18n/cs.json index 66d3a42a..ce5d6ad7 100644 --- a/data-definitions/sas-emoji-v1-i18n/cs.json +++ b/data-definitions/sas-emoji-v1-i18n/cs.json @@ -15,7 +15,7 @@ "Flag": "Vlajka", "Telephone": "Telefon", "Hammer": "Kladivo", - "Key": "Klíč", + "Key": "Klíč ke dveřím", "Lock": "Zámek", "Scissors": "Nůžky", "Paperclip": "Sponka", diff --git a/data-definitions/sas-emoji-v1-i18n/es.json b/data-definitions/sas-emoji-v1-i18n/es.json index 83d75f57..3651aef1 100644 --- a/data-definitions/sas-emoji-v1-i18n/es.json +++ b/data-definitions/sas-emoji-v1-i18n/es.json @@ -11,7 +11,7 @@ "Pencil": "Lápiz", "Key": "Llave", "Hammer": "Martillo", - "Telephone": "Telefono", + "Telephone": "Teléfono", "Train": "Tren", "Bicycle": "Bicicleta", "Ball": "Bola", diff --git a/data-definitions/sas-emoji-v1-i18n/fa.json b/data-definitions/sas-emoji-v1-i18n/fa.json new file mode 100644 index 00000000..621b0fff --- /dev/null +++ b/data-definitions/sas-emoji-v1-i18n/fa.json @@ -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": "سگ" +} diff --git a/data-definitions/sas-emoji-v1-i18n/ja.json b/data-definitions/sas-emoji-v1-i18n/ja.json index 1ad4cf14..73943c42 100644 --- a/data-definitions/sas-emoji-v1-i18n/ja.json +++ b/data-definitions/sas-emoji-v1-i18n/ja.json @@ -9,14 +9,14 @@ "Moon": "月", "Apple": "リンゴ", "Cake": "ケーキ", - "Robot": "ロボと", + "Robot": "ロボット", "Glasses": "めがね", "Book": "本", "Telephone": "電話機", "Train": "電車", "Bicycle": "自転車", "Pin": "ピン", - "Folder": "フォルダ", + "Folder": "フォルダー", "Headphones": "ヘッドホン", "Anchor": "いかり", "Bell": "ベル", diff --git a/data-definitions/sas-emoji-v1-i18n/pt.json b/data-definitions/sas-emoji-v1-i18n/pt.json new file mode 100644 index 00000000..17cc00d6 --- /dev/null +++ b/data-definitions/sas-emoji-v1-i18n/pt.json @@ -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" +} diff --git a/data-definitions/sas-emoji-v1-i18n/sk.json b/data-definitions/sas-emoji-v1-i18n/sk.json index f0a7176c..f44cb0fc 100644 --- a/data-definitions/sas-emoji-v1-i18n/sk.json +++ b/data-definitions/sas-emoji-v1-i18n/sk.json @@ -1,64 +1,64 @@ { - "Dog": "Hlava psa", - "Cat": "Hlava mačky", - "Lion": "Hlava leva", + "Dog": "Pes", + "Cat": "Mačka", + "Lion": "Lev", "Horse": "Kôň", - "Unicorn": "Hlava jednorožca", - "Pig": "Hlava prasaťa", + "Unicorn": "Jednorožec", + "Pig": "Prasa", "Elephant": "Slon", - "Rabbit": "Hlava zajaca", - "Panda": "Hlava pandy", + "Rabbit": "Zajac", + "Panda": "Panda", "Rooster": "Kohút", "Penguin": "Tučniak", "Turtle": "Korytnačka", "Fish": "Ryba", "Octopus": "Chobotnica", "Butterfly": "Motýľ", - "Flower": "Tulipán", - "Tree": "Listnatý strom", + "Flower": "Kvet", + "Tree": "Strom", "Cactus": "Kaktus", "Mushroom": "Huba", "Globe": "Zemeguľa", - "Moon": "Polmesiac", + "Moon": "Mesiac", "Cloud": "Oblak", "Fire": "Oheň", "Banana": "Banán", - "Apple": "Červené jablko", + "Apple": "Jablko", "Strawberry": "Jahoda", - "Corn": "Kukuričný klas", + "Corn": "Kukurica", "Pizza": "Pizza", - "Cake": "Narodeninová torta", - "Heart": "červené srdce", - "Smiley": "Škeriaca sa tvár", + "Cake": "Torta", + "Heart": "Srdce", + "Smiley": "Smajlík", "Robot": "Robot", - "Hat": "Cilinder", + "Hat": "Klobúk", "Glasses": "Okuliare", - "Spanner": "Francúzsky kľúč", - "Santa": "Santa Claus", + "Spanner": "Vidlicový kľúč", + "Santa": "Mikuláš", "Thumbs Up": "Palec nahor", "Umbrella": "Dáždnik", "Hourglass": "Presýpacie hodiny", "Clock": "Budík", - "Gift": "Zabalený darček", + "Gift": "Darček", "Light Bulb": "Žiarovka", - "Book": "Zatvorená kniha", + "Book": "Kniha", "Pencil": "Ceruzka", - "Paperclip": "Sponka na papier", + "Paperclip": "Kancelárska sponka", "Scissors": "Nožnice", - "Lock": "Zatvorená zámka", + "Lock": "Zámka", "Key": "Kľúč", "Hammer": "Kladivo", "Telephone": "Telefón", - "Flag": "Kockovaná zástava", - "Train": "Rušeň", + "Flag": "Zástava", + "Train": "Vlak", "Bicycle": "Bicykel", "Aeroplane": "Lietadlo", "Rocket": "Raketa", "Trophy": "Trofej", - "Ball": "Futbal", + "Ball": "Lopta", "Guitar": "Gitara", "Trumpet": "Trúbka", - "Bell": "Zvon", + "Bell": "Zvonec", "Anchor": "Kotva", "Headphones": "Slúchadlá", "Folder": "Fascikel", diff --git a/data-definitions/sas-emoji-v1-i18n/vi.json b/data-definitions/sas-emoji-v1-i18n/vi.json index f6e146da..76bb4ff1 100644 --- a/data-definitions/sas-emoji-v1-i18n/vi.json +++ b/data-definitions/sas-emoji-v1-i18n/vi.json @@ -17,20 +17,20 @@ "Hammer": "Búa", "Key": "Chìa khóa", "Lock": "Ổ khóa", - "Scissors": "Cây kéo", + "Scissors": "Cái kéo", "Paperclip": "Kẹp giấy", "Pencil": "Viết chì", "Book": "Sách", "Light Bulb": "Bóng đèn tròn", - "Gift": "Quà", + "Gift": "Quà tặng", "Clock": "Đồng hồ", "Hourglass": "Đồng hồ cát", - "Umbrella": "Cây dù", + "Umbrella": "Cái ô", "Thumbs Up": "Thích", - "Santa": "ông già Noel", + "Santa": "ông già Nô-en", "Spanner": "Cờ-lê", - "Glasses": "Mắt kiếng", - "Hat": "Nón", + "Glasses": "Kính mắt", + "Hat": "Mũ", "Robot": "Rô-bô", "Smiley": "Mặt cười", "Heart": "Tim", diff --git a/data-definitions/sas-emoji-v1-i18n/zh_Hant.json b/data-definitions/sas-emoji-v1-i18n/zh_Hant.json new file mode 100644 index 00000000..45dc1f61 --- /dev/null +++ b/data-definitions/sas-emoji-v1-i18n/zh_Hant.json @@ -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": "狗" +} diff --git a/data-definitions/sas-emoji.json b/data-definitions/sas-emoji.json index e6bc02bf..88d551f0 100644 --- a/data-definitions/sas-emoji.json +++ b/data-definitions/sas-emoji.json @@ -5,7 +5,7 @@ "description": "Dog", "unicode": "U+1F436", "translated_descriptions": { - "ar": "كَلب", + "ar": "كلب", "bg": "Куче", "ca": "Gos", "cs": "Pes", @@ -13,6 +13,7 @@ "eo": "Hundo", "es": "Perro", "et": "Koer", + "fa": "سگ", "fi": "Koira", "fr": "Chien", "hr": "pas", @@ -22,10 +23,11 @@ "ja": "犬", "nb_NO": "Hund", "nl": "Hond", + "pt": "Cão", "pt_BR": "Cachorro", "ru": "Собака", "si": "බල්ලා", - "sk": "Hlava psa", + "sk": "Pes", "sq": "Qen", "sr": "пас", "sv": "Hund", @@ -33,7 +35,8 @@ "tzm": "Aydi", "uk": "Пес", "vi": "Chó", - "zh_Hans": "狗" + "zh_Hans": "狗", + "zh_Hant": "狗" } }, { @@ -50,6 +53,7 @@ "eo": "Kato", "es": "Gato", "et": "Kass", + "fa": "گربه", "fi": "Kissa", "fr": "Chat", "hr": "mačka", @@ -59,10 +63,11 @@ "ja": "猫", "nb_NO": "Katt", "nl": "Kat", + "pt": "Gato", "pt_BR": "Gato", "ru": "Кошка", "si": "පූසා", - "sk": "Hlava mačky", + "sk": "Mačka", "sq": "Mace", "sr": "мачка", "sv": "Katt", @@ -70,7 +75,8 @@ "tzm": "Amuc", "uk": "Кіт", "vi": "Mèo", - "zh_Hans": "猫" + "zh_Hans": "猫", + "zh_Hant": "貓" } }, { @@ -87,6 +93,7 @@ "eo": "Leono", "es": "León", "et": "Lõvi", + "fa": "شیر", "fi": "Leijona", "fr": "Lion", "hr": "lav", @@ -96,10 +103,11 @@ "ja": "ライオン", "nb_NO": "Løve", "nl": "Leeuw", + "pt": "Leão", "pt_BR": "Leão", "ru": "Лев", "si": "සිංහයා", - "sk": "Hlava leva", + "sk": "Lev", "sq": "Luan", "sr": "лав", "sv": "Lejon", @@ -107,7 +115,8 @@ "tzm": "Izem", "uk": "Лев", "vi": "Sư tử", - "zh_Hans": "狮子" + "zh_Hans": "狮子", + "zh_Hant": "獅子" } }, { @@ -124,6 +133,7 @@ "eo": "Ĉevalo", "es": "Caballo", "et": "Hobune", + "fa": "اسب", "fi": "Hevonen", "fr": "Cheval", "hr": "konj", @@ -133,6 +143,7 @@ "ja": "馬", "nb_NO": "Hest", "nl": "Paard", + "pt": "Cavalo", "pt_BR": "Cavalo", "ru": "Лошадь", "si": "අශ්වයා", @@ -144,7 +155,8 @@ "tzm": "Ayyis", "uk": "Кінь", "vi": "Ngựa", - "zh_Hans": "马" + "zh_Hans": "马", + "zh_Hant": "馬" } }, { @@ -153,7 +165,7 @@ "description": "Unicorn", "unicode": "U+1F984", "translated_descriptions": { - "ar": "حِصَانٌ بِقَرن", + "ar": "حصان وحيد القرن", "bg": "Еднорог", "ca": "Unicorn", "cs": "Jednorožec", @@ -161,6 +173,7 @@ "eo": "Unukorno", "es": "Unicornio", "et": "Ükssarvik", + "fa": "تک شاخ", "fi": "Yksisarvinen", "fr": "Licorne", "hr": "jednorog", @@ -170,10 +183,11 @@ "ja": "ユニコーン", "nb_NO": "Enhjørning", "nl": "Eenhoorn", + "pt": "Unicórnio", "pt_BR": "Unicórnio", "ru": "Единорог", "si": null, - "sk": "Hlava jednorožca", + "sk": "Jednorožec", "sq": "Njëbrirësh", "sr": "једнорог", "sv": "Enhörning", @@ -181,7 +195,8 @@ "tzm": null, "uk": "Єдиноріг", "vi": "Kỳ lân", - "zh_Hans": "独角兽" + "zh_Hans": "独角兽", + "zh_Hant": "獨角獸" } }, { @@ -198,6 +213,7 @@ "eo": "Porko", "es": "Cerdo", "et": "Siga", + "fa": "خوک", "fi": "Sika", "fr": "Cochon", "hr": "svinja", @@ -207,10 +223,11 @@ "ja": "ブタ", "nb_NO": "Gris", "nl": "Varken", + "pt": "Porco", "pt_BR": "Porco", "ru": "Свинья", "si": null, - "sk": "Hlava prasaťa", + "sk": "Prasa", "sq": "Derr", "sr": "прасе", "sv": "Gris", @@ -218,7 +235,8 @@ "tzm": "Ilef", "uk": "Свиня", "vi": "Heo", - "zh_Hans": "猪" + "zh_Hans": "猪", + "zh_Hant": "豬" } }, { @@ -235,6 +253,7 @@ "eo": "Elefanto", "es": "Elefante", "et": "Elevant", + "fa": "فیل", "fi": "Norsu", "fr": "Éléphant", "hr": "slon", @@ -244,6 +263,7 @@ "ja": "ゾウ", "nb_NO": "Elefant", "nl": "Olifant", + "pt": "Elefante", "pt_BR": "Elefante", "ru": "Слон", "si": null, @@ -255,7 +275,8 @@ "tzm": "Ilu", "uk": "Слон", "vi": "Voi", - "zh_Hans": "大象" + "zh_Hans": "大象", + "zh_Hant": "大象" } }, { @@ -272,6 +293,7 @@ "eo": "Kuniklo", "es": "Conejo", "et": "Jänes", + "fa": "خرگوش", "fi": "Kani", "fr": "Lapin", "hr": "zec", @@ -281,10 +303,11 @@ "ja": "うさぎ", "nb_NO": "Kanin", "nl": "Konijn", + "pt": "Coelho", "pt_BR": "Coelho", "ru": "Кролик", "si": null, - "sk": "Hlava zajaca", + "sk": "Zajac", "sq": "Lepur", "sr": "зец", "sv": "Kanin", @@ -292,7 +315,8 @@ "tzm": "Agnin", "uk": "Кріль", "vi": "Thỏ", - "zh_Hans": "兔子" + "zh_Hans": "兔子", + "zh_Hant": "兔子" } }, { @@ -309,6 +333,7 @@ "eo": "Pando", "es": "Panda", "et": "Panda", + "fa": "پاندا", "fi": "Panda", "fr": "Panda", "hr": "panda", @@ -318,10 +343,11 @@ "ja": "パンダ", "nb_NO": "Panda", "nl": "Panda", + "pt": "Panda", "pt_BR": "Panda", "ru": "Панда", "si": null, - "sk": "Hlava pandy", + "sk": "Panda", "sq": "Panda", "sr": "панда", "sv": "Panda", @@ -329,7 +355,8 @@ "tzm": null, "uk": "Панда", "vi": "Gấu trúc", - "zh_Hans": "熊猫" + "zh_Hans": "熊猫", + "zh_Hant": "熊貓" } }, { @@ -346,6 +373,7 @@ "eo": "Virkoko", "es": "Gallo", "et": "Kukk", + "fa": "خروس", "fi": "Kukko", "fr": "Coq", "hr": "kokot", @@ -355,6 +383,7 @@ "ja": "ニワトリ", "nb_NO": "Hane", "nl": "Haan", + "pt": "Galo", "pt_BR": "Galo", "ru": "Петух", "si": null, @@ -366,7 +395,8 @@ "tzm": "Ayaẓiḍ", "uk": "Когут", "vi": "Gà trống", - "zh_Hans": "公鸡" + "zh_Hans": "公鸡", + "zh_Hant": "公雞" } }, { @@ -375,7 +405,7 @@ "description": "Penguin", "unicode": "U+1F427", "translated_descriptions": { - "ar": "بِطريق", + "ar": "بطريق", "bg": "Пингвин", "ca": "Pingüí", "cs": "Tučňák", @@ -383,6 +413,7 @@ "eo": "Pingveno", "es": "Pingüino", "et": "Pingviin", + "fa": "پنگوئن", "fi": "Pingviini", "fr": "Manchot", "hr": "pingvin", @@ -392,6 +423,7 @@ "ja": "ペンギン", "nb_NO": "Pingvin", "nl": "Pinguïn", + "pt": "Pinguim", "pt_BR": "Pinguim", "ru": "Пингвин", "si": null, @@ -403,7 +435,8 @@ "tzm": null, "uk": "Пінгвін", "vi": "Chim cánh cụt", - "zh_Hans": "企鹅" + "zh_Hans": "企鹅", + "zh_Hant": "企鵝" } }, { @@ -420,6 +453,7 @@ "eo": "Testudo", "es": "Tortuga", "et": "Kilpkonn", + "fa": "لاک‌پشت", "fi": "Kilpikonna", "fr": "Tortue", "hr": "kornjača", @@ -429,6 +463,7 @@ "ja": "亀", "nb_NO": "Skilpadde", "nl": "Schildpad", + "pt": "Tartaruga", "pt_BR": "Tartaruga", "ru": "Черепаха", "si": null, @@ -440,7 +475,8 @@ "tzm": "Ifker", "uk": "Черепаха", "vi": "Rùa", - "zh_Hans": "乌龟" + "zh_Hans": "乌龟", + "zh_Hant": "烏龜" } }, { @@ -449,7 +485,7 @@ "description": "Fish", "unicode": "U+1F41F", "translated_descriptions": { - "ar": "سَمَكَة", + "ar": "سَمَكة", "bg": "Риба", "ca": "Peix", "cs": "Ryba", @@ -457,6 +493,7 @@ "eo": "Fiŝo", "es": "Pez", "et": "Kala", + "fa": "ماهی", "fi": "Kala", "fr": "Poisson", "hr": "riba", @@ -466,6 +503,7 @@ "ja": "魚", "nb_NO": "Fisk", "nl": "Vis", + "pt": "Peixe", "pt_BR": "Peixe", "ru": "Рыба", "si": null, @@ -477,7 +515,8 @@ "tzm": "Aselm", "uk": "Риба", "vi": "Cá", - "zh_Hans": "鱼" + "zh_Hans": "鱼", + "zh_Hant": "魚" } }, { @@ -494,6 +533,7 @@ "eo": "Polpo", "es": "Pulpo", "et": "Kaheksajalg", + "fa": "اختاپوس", "fi": "Tursas", "fr": "Poulpe", "hr": "hobotnica", @@ -503,6 +543,7 @@ "ja": "たこ", "nb_NO": "Blekksprut", "nl": "Octopus", + "pt": "Polvo", "pt_BR": "Polvo", "ru": "Осьминог", "si": null, @@ -514,7 +555,8 @@ "tzm": null, "uk": "Восьминіг", "vi": "Bạch tuộc", - "zh_Hans": "章鱼" + "zh_Hans": "章鱼", + "zh_Hant": "章魚" } }, { @@ -531,6 +573,7 @@ "eo": "Papilio", "es": "Mariposa", "et": "Liblikas", + "fa": "پروانه", "fi": "Perhonen", "fr": "Papillon", "hr": "leptir", @@ -540,6 +583,7 @@ "ja": "ちょうちょ", "nb_NO": "Sommerfugl", "nl": "Vlinder", + "pt": "Borboleta", "pt_BR": "Borboleta", "ru": "Бабочка", "si": null, @@ -551,7 +595,8 @@ "tzm": null, "uk": "Метелик", "vi": "Bướm", - "zh_Hans": "蝴蝶" + "zh_Hans": "蝴蝶", + "zh_Hant": "蝴蝶" } }, { @@ -568,6 +613,7 @@ "eo": "Floro", "es": "Flor", "et": "Lill", + "fa": "گل", "fi": "Kukka", "fr": "Fleur", "hr": "svijet", @@ -577,10 +623,11 @@ "ja": "花", "nb_NO": "Blomst", "nl": "Bloem", + "pt": "Flor", "pt_BR": "Flor", "ru": "Цветок", "si": null, - "sk": "Tulipán", + "sk": "Kvet", "sq": "Lule", "sr": "цвет", "sv": "Blomma", @@ -588,7 +635,8 @@ "tzm": null, "uk": "Квітка", "vi": "Hoa", - "zh_Hans": "花" + "zh_Hans": "花", + "zh_Hant": "花" } }, { @@ -605,6 +653,7 @@ "eo": "Arbo", "es": "Árbol", "et": "Puu", + "fa": "درخت", "fi": "Puu", "fr": "Arbre", "hr": "drvo", @@ -614,10 +663,11 @@ "ja": "木", "nb_NO": "Tre", "nl": "Boom", + "pt": "Árvore", "pt_BR": "Árvore", "ru": "Дерево", "si": null, - "sk": "Listnatý strom", + "sk": "Strom", "sq": "Pemë", "sr": "дрво", "sv": "Träd", @@ -625,7 +675,8 @@ "tzm": "Aseklu", "uk": "Дерево", "vi": "Cây", - "zh_Hans": "树" + "zh_Hans": "树", + "zh_Hant": "樹" } }, { @@ -642,6 +693,7 @@ "eo": "Kakto", "es": "Cactus", "et": "Kaktus", + "fa": "کاکتوس", "fi": "Kaktus", "fr": "Cactus", "hr": "kaktus", @@ -651,6 +703,7 @@ "ja": "サボテン", "nb_NO": "Kaktus", "nl": "Cactus", + "pt": "Cato", "pt_BR": "Cacto", "ru": "Кактус", "si": null, @@ -662,7 +715,8 @@ "tzm": null, "uk": "Кактус", "vi": "Xương rồng", - "zh_Hans": "仙人掌" + "zh_Hans": "仙人掌", + "zh_Hant": "仙人掌" } }, { @@ -679,6 +733,7 @@ "eo": "Fungo", "es": "Seta", "et": "Seen", + "fa": "قارچ", "fi": "Sieni", "fr": "Champignon", "hr": "gljiva", @@ -688,6 +743,7 @@ "ja": "きのこ", "nb_NO": "Sopp", "nl": "Paddenstoel", + "pt": "Cogumelo", "pt_BR": "Cogumelo", "ru": "Гриб", "si": null, @@ -699,7 +755,8 @@ "tzm": "Agursel", "uk": "Гриб", "vi": "Nấm", - "zh_Hans": "蘑菇" + "zh_Hans": "蘑菇", + "zh_Hant": "蘑菇" } }, { @@ -716,6 +773,7 @@ "eo": "Globo", "es": "Globo", "et": "Maakera", + "fa": "زمین", "fi": "Maapallo", "fr": "Globe", "hr": "Globus", @@ -725,6 +783,7 @@ "ja": "地球", "nb_NO": "Globus", "nl": "Wereldbol", + "pt": "Globo", "pt_BR": "Globo", "ru": "Глобус", "si": null, @@ -736,7 +795,8 @@ "tzm": null, "uk": "Глобус", "vi": "Địa cầu", - "zh_Hans": "地球" + "zh_Hans": "地球", + "zh_Hant": "地球" } }, { @@ -753,6 +813,7 @@ "eo": "Luno", "es": "Luna", "et": "Kuu", + "fa": "ماه", "fi": "Kuu", "fr": "Lune", "hr": "mjesec", @@ -762,10 +823,11 @@ "ja": "月", "nb_NO": "Måne", "nl": "Maan", + "pt": "Lua", "pt_BR": "Lua", "ru": "Луна", "si": null, - "sk": "Polmesiac", + "sk": "Mesiac", "sq": "Hënë", "sr": "месец", "sv": "Måne", @@ -773,7 +835,8 @@ "tzm": "Ayyur", "uk": "Місяць", "vi": "Mặt trăng", - "zh_Hans": "月亮" + "zh_Hans": "月亮", + "zh_Hant": "月亮" } }, { @@ -790,6 +853,7 @@ "eo": "Nubo", "es": "Nube", "et": "Pilv", + "fa": "ابر", "fi": "Pilvi", "fr": "Nuage", "hr": "oblak", @@ -799,6 +863,7 @@ "ja": "雲", "nb_NO": "Sky", "nl": "Wolk", + "pt": "Nuvem", "pt_BR": "Nuvem", "ru": "Облако", "si": null, @@ -810,7 +875,8 @@ "tzm": null, "uk": "Хмара", "vi": "Mây", - "zh_Hans": "云" + "zh_Hans": "云", + "zh_Hant": "雲朵" } }, { @@ -827,6 +893,7 @@ "eo": "Fajro", "es": "Fuego", "et": "Tuli", + "fa": "آتش", "fi": "Tuli", "fr": "Feu", "hr": "vatra", @@ -836,6 +903,7 @@ "ja": "炎", "nb_NO": "Flamme", "nl": "Vuur", + "pt": "Fogo", "pt_BR": "Fogo", "ru": "Огонь", "si": null, @@ -847,7 +915,8 @@ "tzm": "Timessi", "uk": "Вогонь", "vi": "Lửa", - "zh_Hans": "火" + "zh_Hans": "火", + "zh_Hant": "火" } }, { @@ -864,6 +933,7 @@ "eo": "Banano", "es": "Plátano", "et": "Banaan", + "fa": "موز", "fi": "Banaani", "fr": "Banane", "hr": "banana", @@ -873,6 +943,7 @@ "ja": "バナナ", "nb_NO": "Banan", "nl": "Banaan", + "pt": "Banana", "pt_BR": "Banana", "ru": "Банан", "si": null, @@ -884,7 +955,8 @@ "tzm": "Tabanant", "uk": "Банан", "vi": "Chuối", - "zh_Hans": "香蕉" + "zh_Hans": "香蕉", + "zh_Hant": "香蕉" } }, { @@ -901,6 +973,7 @@ "eo": "Pomo", "es": "Manzana", "et": "Õun", + "fa": "سیب", "fi": "Omena", "fr": "Pomme", "hr": "jabuka", @@ -910,10 +983,11 @@ "ja": "リンゴ", "nb_NO": "Eple", "nl": "Appel", + "pt": "Maçã", "pt_BR": "Maçã", "ru": "Яблоко", "si": null, - "sk": "Červené jablko", + "sk": "Jablko", "sq": "Mollë", "sr": "јабука", "sv": "Äpple", @@ -921,7 +995,8 @@ "tzm": "Tadeffuyt", "uk": "Яблуко", "vi": "Táo", - "zh_Hans": "苹果" + "zh_Hans": "苹果", + "zh_Hant": "蘋果" } }, { @@ -938,6 +1013,7 @@ "eo": "Frago", "es": "Fresa", "et": "Maasikas", + "fa": "توت فرنگی", "fi": "Mansikka", "fr": "Fraise", "hr": "jagoda", @@ -947,6 +1023,7 @@ "ja": "いちご", "nb_NO": "Jordbær", "nl": "Aardbei", + "pt": "Morango", "pt_BR": "Morango", "ru": "Клубника", "si": null, @@ -958,7 +1035,8 @@ "tzm": null, "uk": "Полуниця", "vi": "Dâu tây", - "zh_Hans": "草莓" + "zh_Hans": "草莓", + "zh_Hant": "草莓" } }, { @@ -975,6 +1053,7 @@ "eo": "Maizo", "es": "Maíz", "et": "Mais", + "fa": "ذرت", "fi": "Maissi", "fr": "Maïs", "hr": "kukuruza", @@ -984,10 +1063,11 @@ "ja": "とうもろこし", "nb_NO": "Mais", "nl": "Maïs", + "pt": "Milho", "pt_BR": "Milho", "ru": "Кукуруза", "si": null, - "sk": "Kukuričný klas", + "sk": "Kukurica", "sq": "Misër", "sr": "кукуруз", "sv": "Majs", @@ -995,7 +1075,8 @@ "tzm": null, "uk": "Кукурудза", "vi": "Bắp", - "zh_Hans": "玉米" + "zh_Hans": "玉米", + "zh_Hant": "玉米" } }, { @@ -1012,6 +1093,7 @@ "eo": "Pico", "es": "Pizza", "et": "Pitsa", + "fa": "پیتزا", "fi": "Pizza", "fr": "Pizza", "hr": "pizza", @@ -1021,6 +1103,7 @@ "ja": "ピザ", "nb_NO": "Pizza", "nl": "Pizza", + "pt": "Piza", "pt_BR": "Pizza", "ru": "Пицца", "si": null, @@ -1032,7 +1115,8 @@ "tzm": null, "uk": "Піца", "vi": "Pizza", - "zh_Hans": "披萨" + "zh_Hans": "披萨", + "zh_Hant": "披薩" } }, { @@ -1049,6 +1133,7 @@ "eo": "Torto", "es": "Tarta", "et": "Kook", + "fa": "کیک", "fi": "Kakku", "fr": "Gâteau", "hr": "torta", @@ -1058,10 +1143,11 @@ "ja": "ケーキ", "nb_NO": "Kake", "nl": "Taart", + "pt": "Bolo", "pt_BR": "Bolo", "ru": "Торт", "si": null, - "sk": "Narodeninová torta", + "sk": "Torta", "sq": "Tortë", "sr": "торта", "sv": "Tårta", @@ -1069,7 +1155,8 @@ "tzm": null, "uk": "Пиріг", "vi": "Bánh", - "zh_Hans": "蛋糕" + "zh_Hans": "蛋糕", + "zh_Hant": "蛋糕" } }, { @@ -1086,6 +1173,7 @@ "eo": "Koro", "es": "Corazón", "et": "Süda", + "fa": "قلب", "fi": "Sydän", "fr": "Cœur", "hr": "srca", @@ -1095,10 +1183,11 @@ "ja": "ハート", "nb_NO": "Hjerte", "nl": "Hart", + "pt": "Coração", "pt_BR": "Coração", "ru": "Сердце", "si": null, - "sk": "červené srdce", + "sk": "Srdce", "sq": "Zemër", "sr": "срце", "sv": "Hjärta", @@ -1106,7 +1195,8 @@ "tzm": "Ul", "uk": "Серце", "vi": "Tim", - "zh_Hans": "心" + "zh_Hans": "心", + "zh_Hant": "愛心" } }, { @@ -1123,6 +1213,7 @@ "eo": "Rideto", "es": "Emoticono", "et": "Smaili", + "fa": "خنده", "fi": "Hymynaama", "fr": "Sourire", "hr": "smajlića", @@ -1132,10 +1223,11 @@ "ja": "スマイル", "nb_NO": "Smilefjes", "nl": "Smiley", + "pt": "Sorriso", "pt_BR": "Sorriso", "ru": "Улыбка", "si": null, - "sk": "Škeriaca sa tvár", + "sk": "Smajlík", "sq": "Emotikon", "sr": "смајли", "sv": "Smiley", @@ -1143,7 +1235,8 @@ "tzm": null, "uk": "Посмішка", "vi": "Mặt cười", - "zh_Hans": "笑脸" + "zh_Hans": "笑脸", + "zh_Hant": "笑臉" } }, { @@ -1160,15 +1253,17 @@ "eo": "Roboto", "es": "Robot", "et": "Robot", + "fa": "ربات", "fi": "Robotti", "fr": "Robot", "hr": "robot", "hu": "Robot", "id": "Robot", "it": "Robot", - "ja": "ロボと", + "ja": "ロボット", "nb_NO": "Robot", "nl": "Robot", + "pt": "Robô", "pt_BR": "Robô", "ru": "Робот", "si": null, @@ -1180,7 +1275,8 @@ "tzm": "Aṛubu", "uk": "Робот", "vi": "Rô-bô", - "zh_Hans": "机器人" + "zh_Hans": "机器人", + "zh_Hant": "機器人" } }, { @@ -1197,6 +1293,7 @@ "eo": "Ĉapelo", "es": "Sombrero", "et": "Kübar", + "fa": "کلاه", "fi": "Hattu", "fr": "Chapeau", "hr": "kapa", @@ -1206,18 +1303,20 @@ "ja": "帽子", "nb_NO": "Hatt", "nl": "Hoed", + "pt": "Chapéu", "pt_BR": "Chapéu", "ru": "Шляпа", "si": null, - "sk": "Cilinder", + "sk": "Klobúk", "sq": "Kapë", "sr": "шешир", "sv": "Hatt", "szl": null, "tzm": "Taraza", "uk": "Капелюх", - "vi": "Nón", - "zh_Hans": "帽子" + "vi": "Mũ", + "zh_Hans": "帽子", + "zh_Hant": "帽子" } }, { @@ -1234,6 +1333,7 @@ "eo": "Okulvitroj", "es": "Gafas", "et": "Prillid", + "fa": "عینک", "fi": "Silmälasit", "fr": "Lunettes", "hr": "naočale", @@ -1243,6 +1343,7 @@ "ja": "めがね", "nb_NO": "Briller", "nl": "Bril", + "pt": "Óculos", "pt_BR": "Óculos", "ru": "Очки", "si": null, @@ -1253,8 +1354,9 @@ "szl": null, "tzm": null, "uk": "Окуляри", - "vi": "Mắt kiếng", - "zh_Hans": "眼镜" + "vi": "Kính mắt", + "zh_Hans": "眼镜", + "zh_Hant": "眼鏡" } }, { @@ -1271,6 +1373,7 @@ "eo": "Ŝraŭbŝlosilo", "es": "Llave inglesa", "et": "Mutrivõti", + "fa": "آچار", "fi": "Kiintoavain", "fr": "Clé à molette", "hr": "ključ", @@ -1280,10 +1383,11 @@ "ja": "スパナ", "nb_NO": "Fastnøkkel", "nl": "Moersleutel", + "pt": "Chave inglesa", "pt_BR": "Chave inglesa", "ru": "Ключ", "si": null, - "sk": "Francúzsky kľúč", + "sk": "Vidlicový kľúč", "sq": "Çelës", "sr": "кључ", "sv": "Skruvnyckel", @@ -1291,7 +1395,8 @@ "tzm": null, "uk": "Гайковий ключ", "vi": "Cờ-lê", - "zh_Hans": "扳手" + "zh_Hans": "扳手", + "zh_Hant": "扳手" } }, { @@ -1308,6 +1413,7 @@ "eo": "Kristnaska viro", "es": "Papá Noel", "et": "Jõuluvana", + "fa": "بابا نوئل", "fi": "Joulupukki", "fr": "Père Noël", "hr": "deda Mraz", @@ -1317,18 +1423,20 @@ "ja": "サンタ", "nb_NO": "Julenisse", "nl": "Kerstman", + "pt": "Pai Natal", "pt_BR": "Papai-noel", "ru": "Санта", "si": null, - "sk": "Santa Claus", + "sk": "Mikuláš", "sq": "Babagjyshi i Vitit të Ri", "sr": "деда Мраз", "sv": "Tomte", "szl": null, "tzm": null, "uk": "Санта Клаус", - "vi": "ông già Noel", - "zh_Hans": "圣诞老人" + "vi": "ông già Nô-en", + "zh_Hans": "圣诞老人", + "zh_Hant": "聖誕老人" } }, { @@ -1345,6 +1453,7 @@ "eo": "Dikfingro supren", "es": "Pulgar arriba", "et": "Pöidlad püsti", + "fa": "لایک", "fi": "Peukalo ylös", "fr": "Pouce en l’air", "hr": "palac gore", @@ -1354,6 +1463,7 @@ "ja": "いいね", "nb_NO": "Tommel Opp", "nl": "Duim omhoog", + "pt": "Polegar para cima", "pt_BR": "Joinha", "ru": "Большой палец вверх", "si": null, @@ -1365,7 +1475,8 @@ "tzm": null, "uk": "Великий палець вгору", "vi": "Thích", - "zh_Hans": "赞" + "zh_Hans": "赞", + "zh_Hant": "讚" } }, { @@ -1382,6 +1493,7 @@ "eo": "Ombrelo", "es": "Paraguas", "et": "Vihmavari", + "fa": "چتر", "fi": "Sateenvarjo", "fr": "Parapluie", "hr": "kišobran", @@ -1391,6 +1503,7 @@ "ja": "傘", "nb_NO": "Paraply", "nl": "Paraplu", + "pt": "Guarda-chuva", "pt_BR": "Guarda-chuva", "ru": "Зонт", "si": null, @@ -1401,8 +1514,9 @@ "szl": null, "tzm": null, "uk": "Парасолька", - "vi": "Cây dù", - "zh_Hans": "伞" + "vi": "Cái ô", + "zh_Hans": "伞", + "zh_Hant": "雨傘" } }, { @@ -1419,6 +1533,7 @@ "eo": "Sablohorloĝo", "es": "Reloj de arena", "et": "Liivakell", + "fa": "ساعت شنی", "fi": "Tiimalasi", "fr": "Sablier", "hr": "pješčani sat", @@ -1428,6 +1543,7 @@ "ja": "砂時計", "nb_NO": "Timeglass", "nl": "Zandloper", + "pt": "Ampulheta", "pt_BR": "Ampulheta", "ru": "Песочные часы", "si": null, @@ -1439,7 +1555,8 @@ "tzm": null, "uk": "Пісковий годинник", "vi": "Đồng hồ cát", - "zh_Hans": "沙漏" + "zh_Hans": "沙漏", + "zh_Hant": "沙漏" } }, { @@ -1456,6 +1573,7 @@ "eo": "Horloĝo", "es": "Reloj", "et": "Kell", + "fa": "ساعت", "fi": "Pöytäkello", "fr": "Réveil", "hr": "sat", @@ -1465,6 +1583,7 @@ "ja": "時計", "nb_NO": "Klokke", "nl": "Wekker", + "pt": "Relógio", "pt_BR": "Relógio", "ru": "Часы", "si": null, @@ -1476,7 +1595,8 @@ "tzm": null, "uk": "Годинник", "vi": "Đồng hồ", - "zh_Hans": "时钟" + "zh_Hans": "时钟", + "zh_Hant": "時鐘" } }, { @@ -1493,6 +1613,7 @@ "eo": "Donaco", "es": "Regalo", "et": "Kingitus", + "fa": "هدیه", "fi": "Lahja", "fr": "Cadeau", "hr": "poklon", @@ -1502,18 +1623,20 @@ "ja": "ギフト", "nb_NO": "Gave", "nl": "Geschenk", + "pt": "Presente", "pt_BR": "Presente", "ru": "Подарок", "si": null, - "sk": "Zabalený darček", + "sk": "Darček", "sq": "Dhuratë", "sr": "поклон", "sv": "Present", "szl": null, "tzm": null, "uk": "Подарунок", - "vi": "Quà", - "zh_Hans": "礼物" + "vi": "Quà tặng", + "zh_Hans": "礼物", + "zh_Hant": "禮物" } }, { @@ -1530,6 +1653,7 @@ "eo": "Lampo", "es": "Bombilla", "et": "Lambipirn", + "fa": "لامپ", "fi": "Hehkulamppu", "fr": "Ampoule", "hr": "žarulja", @@ -1539,6 +1663,7 @@ "ja": "電球", "nb_NO": "Lyspære", "nl": "Gloeilamp", + "pt": "Lâmpada", "pt_BR": "Lâmpada", "ru": "Лампочка", "si": null, @@ -1550,7 +1675,8 @@ "tzm": null, "uk": "Лампочка", "vi": "Bóng đèn tròn", - "zh_Hans": "灯泡" + "zh_Hans": "灯泡", + "zh_Hant": "燈泡" } }, { @@ -1567,6 +1693,7 @@ "eo": "Libro", "es": "Libro", "et": "Raamat", + "fa": "کتاب", "fi": "Kirja", "fr": "Livre", "hr": "knjiga", @@ -1576,10 +1703,11 @@ "ja": "本", "nb_NO": "Bok", "nl": "Boek", + "pt": "Livro", "pt_BR": "Livro", "ru": "Книга", "si": null, - "sk": "Zatvorená kniha", + "sk": "Kniha", "sq": "Libër", "sr": "књига", "sv": "Bok", @@ -1587,7 +1715,8 @@ "tzm": "Adlis", "uk": "Книга", "vi": "Sách", - "zh_Hans": "书" + "zh_Hans": "书", + "zh_Hant": "書" } }, { @@ -1604,6 +1733,7 @@ "eo": "Krajono", "es": "Lápiz", "et": "Pliiats", + "fa": "مداد", "fi": "Lyijykynä", "fr": "Crayon", "hr": "olovka", @@ -1613,6 +1743,7 @@ "ja": "鉛筆", "nb_NO": "Blyant", "nl": "Potlood", + "pt": "Lápis", "pt_BR": "Lápis", "ru": "Карандаш", "si": null, @@ -1624,7 +1755,8 @@ "tzm": null, "uk": "Олівець", "vi": "Viết chì", - "zh_Hans": "铅笔" + "zh_Hans": "铅笔", + "zh_Hant": "鉛筆" } }, { @@ -1641,6 +1773,7 @@ "eo": "Paperkuntenilo", "es": "Clip", "et": "Kirjaklamber", + "fa": "گیره کاغذ", "fi": "Paperiliitin", "fr": "Trombone", "hr": "spajalica", @@ -1650,10 +1783,11 @@ "ja": "クリップ", "nb_NO": "BInders", "nl": "Papierklemmetje", + "pt": "Clipe", "pt_BR": "Clipe de papel", "ru": "Скрепка", "si": null, - "sk": "Sponka na papier", + "sk": "Kancelárska sponka", "sq": "Kapëse", "sr": "спајалица", "sv": "Gem", @@ -1661,7 +1795,8 @@ "tzm": null, "uk": "Спиначка", "vi": "Kẹp giấy", - "zh_Hans": "回形针" + "zh_Hans": "回形针", + "zh_Hant": "迴紋針" } }, { @@ -1678,6 +1813,7 @@ "eo": "Tondilo", "es": "Tijeras", "et": "Käärid", + "fa": "قیچی", "fi": "Sakset", "fr": "Ciseaux", "hr": "škare", @@ -1687,6 +1823,7 @@ "ja": "はさみ", "nb_NO": "Saks", "nl": "Schaar", + "pt": "Tesoura", "pt_BR": "Tesoura", "ru": "Ножницы", "si": null, @@ -1697,8 +1834,9 @@ "szl": null, "tzm": null, "uk": "Ножиці", - "vi": "Cây kéo", - "zh_Hans": "剪刀" + "vi": "Cái kéo", + "zh_Hans": "剪刀", + "zh_Hant": "剪刀" } }, { @@ -1715,6 +1853,7 @@ "eo": "Seruro", "es": "Candado", "et": "Lukk", + "fa": "قفل", "fi": "Lukko", "fr": "Cadenas", "hr": "zaključati", @@ -1724,10 +1863,11 @@ "ja": "錠前", "nb_NO": "Lås", "nl": "Slot", + "pt": "Cadeado", "pt_BR": "Cadeado", "ru": "Замок", "si": null, - "sk": "Zatvorená zámka", + "sk": "Zámka", "sq": "Dry", "sr": "катанац", "sv": "Lås", @@ -1735,7 +1875,8 @@ "tzm": null, "uk": "Замок", "vi": "Ổ khóa", - "zh_Hans": "锁" + "zh_Hans": "锁", + "zh_Hant": "鎖頭" } }, { @@ -1747,11 +1888,12 @@ "ar": "مِفتَاح", "bg": "Ключ", "ca": "Clau", - "cs": "Klíč", + "cs": "Klíč ke dveřím", "de": "Schlüssel", "eo": "Ŝlosilo", "es": "Llave", "et": "Võti", + "fa": "کلید", "fi": "Avain", "fr": "Clé", "hr": "ključ", @@ -1761,6 +1903,7 @@ "ja": "鍵", "nb_NO": "Nøkkel", "nl": "Sleutel", + "pt": "Chave", "pt_BR": "Chave", "ru": "Ключ", "si": null, @@ -1772,7 +1915,8 @@ "tzm": "Tasarut", "uk": "Ключ", "vi": "Chìa khóa", - "zh_Hans": "钥匙" + "zh_Hans": "钥匙", + "zh_Hant": "鑰匙" } }, { @@ -1789,6 +1933,7 @@ "eo": "Martelo", "es": "Martillo", "et": "Haamer", + "fa": "چکش", "fi": "Vasara", "fr": "Marteau", "hr": "čekić", @@ -1798,6 +1943,7 @@ "ja": "金槌", "nb_NO": "Hammer", "nl": "Hamer", + "pt": "Martelo", "pt_BR": "Martelo", "ru": "Молоток", "si": null, @@ -1809,7 +1955,8 @@ "tzm": null, "uk": "Молоток", "vi": "Búa", - "zh_Hans": "锤子" + "zh_Hans": "锤子", + "zh_Hant": "鎚子" } }, { @@ -1824,8 +1971,9 @@ "cs": "Telefon", "de": "Telefon", "eo": "Telefono", - "es": "Telefono", + "es": "Teléfono", "et": "Telefon", + "fa": "تلفن", "fi": "Puhelin", "fr": "Téléphone", "hr": "telefon", @@ -1835,6 +1983,7 @@ "ja": "電話機", "nb_NO": "Telefon", "nl": "Telefoon", + "pt": "Telefone", "pt_BR": "Telefone", "ru": "Телефон", "si": null, @@ -1846,7 +1995,8 @@ "tzm": "Atilifun", "uk": "Телефон", "vi": "Điện thoại", - "zh_Hans": "电话" + "zh_Hans": "电话", + "zh_Hant": "電話" } }, { @@ -1863,6 +2013,7 @@ "eo": "Flago", "es": "Bandera", "et": "Lipp", + "fa": "پرچم", "fi": "Lippu", "fr": "Drapeau", "hr": "zastava", @@ -1872,10 +2023,11 @@ "ja": "旗", "nb_NO": "Flagg", "nl": "Vlag", + "pt": "Bandeira", "pt_BR": "Bandeira", "ru": "Флаг", "si": null, - "sk": "Kockovaná zástava", + "sk": "Zástava", "sq": "Flamur", "sr": "застава", "sv": "Flagga", @@ -1883,7 +2035,8 @@ "tzm": "Acenyal", "uk": "Прапор", "vi": "Lá cờ", - "zh_Hans": "旗帜" + "zh_Hans": "旗帜", + "zh_Hant": "旗幟" } }, { @@ -1900,6 +2053,7 @@ "eo": "Vagonaro", "es": "Tren", "et": "Rong", + "fa": "قطار", "fi": "Juna", "fr": "Train", "hr": "vlak", @@ -1909,10 +2063,11 @@ "ja": "電車", "nb_NO": "Tog", "nl": "Trein", + "pt": "Comboio", "pt_BR": "Trem", "ru": "Поезд", "si": null, - "sk": "Rušeň", + "sk": "Vlak", "sq": "Tren", "sr": "воз", "sv": "Tåg", @@ -1920,7 +2075,8 @@ "tzm": null, "uk": "Потяг", "vi": "Xe lửa", - "zh_Hans": "火车" + "zh_Hans": "火车", + "zh_Hant": "火車" } }, { @@ -1937,6 +2093,7 @@ "eo": "Biciklo", "es": "Bicicleta", "et": "Jalgratas", + "fa": "دوچرخه", "fi": "Polkupyörä", "fr": "Vélo", "hr": "bicikl", @@ -1946,6 +2103,7 @@ "ja": "自転車", "nb_NO": "Sykkel", "nl": "Fiets", + "pt": "Bicicleta", "pt_BR": "Bicicleta", "ru": "Велосипед", "si": null, @@ -1957,7 +2115,8 @@ "tzm": null, "uk": "Велосипед", "vi": "Xe đạp", - "zh_Hans": "自行车" + "zh_Hans": "自行车", + "zh_Hant": "腳踏車" } }, { @@ -1974,6 +2133,7 @@ "eo": "Aviadilo", "es": "Avión", "et": "Lennuk", + "fa": "هواپیما", "fi": "Lentokone", "fr": "Avion", "hr": "avion", @@ -1983,6 +2143,7 @@ "ja": "飛行機", "nb_NO": "Fly", "nl": "Vliegtuig", + "pt": "Avião", "pt_BR": "Avião", "ru": "Самолет", "si": null, @@ -1994,7 +2155,8 @@ "tzm": null, "uk": "Літак", "vi": "Máy bay", - "zh_Hans": "飞机" + "zh_Hans": "飞机", + "zh_Hant": "飛機" } }, { @@ -2011,6 +2173,7 @@ "eo": "Raketo", "es": "Cohete", "et": "Rakett", + "fa": "موشک", "fi": "Raketti", "fr": "Fusée", "hr": "raketa", @@ -2020,6 +2183,7 @@ "ja": "ロケット", "nb_NO": "Rakett", "nl": "Raket", + "pt": "Foguetão", "pt_BR": "Foguete", "ru": "Ракета", "si": null, @@ -2031,7 +2195,8 @@ "tzm": null, "uk": "Ракета", "vi": "Tên lửa", - "zh_Hans": "火箭" + "zh_Hans": "火箭", + "zh_Hant": "火箭" } }, { @@ -2048,6 +2213,7 @@ "eo": "Trofeo", "es": "Trofeo", "et": "Auhind", + "fa": "جام", "fi": "Palkinto", "fr": "Trophée", "hr": "trofej", @@ -2057,6 +2223,7 @@ "ja": "トロフィー", "nb_NO": "Pokal", "nl": "Trofee", + "pt": "Troféu", "pt_BR": "Troféu", "ru": "Кубок", "si": null, @@ -2068,7 +2235,8 @@ "tzm": null, "uk": "Приз", "vi": "Cúp", - "zh_Hans": "奖杯" + "zh_Hans": "奖杯", + "zh_Hant": "獎盃" } }, { @@ -2085,6 +2253,7 @@ "eo": "Pilko", "es": "Bola", "et": "Pall", + "fa": "توپ", "fi": "Pallo", "fr": "Ballon", "hr": "lopta", @@ -2094,10 +2263,11 @@ "ja": "ボール", "nb_NO": "Ball", "nl": "Bal", + "pt": "Bola", "pt_BR": "Bola", "ru": "Мяч", "si": null, - "sk": "Futbal", + "sk": "Lopta", "sq": "Top", "sr": "лопта", "sv": "Boll", @@ -2105,7 +2275,8 @@ "tzm": "Tcama", "uk": "М'яч", "vi": "Banh", - "zh_Hans": "球" + "zh_Hans": "球", + "zh_Hant": "足球" } }, { @@ -2122,6 +2293,7 @@ "eo": "Gitaro", "es": "Guitarra", "et": "Kitarr", + "fa": "گیتار", "fi": "Kitara", "fr": "Guitare", "hr": "gitara", @@ -2131,6 +2303,7 @@ "ja": "ギター", "nb_NO": "Gitar", "nl": "Gitaar", + "pt": "Guitarra", "pt_BR": "Guitarra", "ru": "Гитара", "si": null, @@ -2142,7 +2315,8 @@ "tzm": "Agiṭaṛ", "uk": "Гітара", "vi": "Ghi-ta", - "zh_Hans": "吉他" + "zh_Hans": "吉他", + "zh_Hant": "吉他" } }, { @@ -2159,6 +2333,7 @@ "eo": "Trumpeto", "es": "Trompeta", "et": "Trompet", + "fa": "شیپور", "fi": "Trumpetti", "fr": "Trompette", "hr": "truba", @@ -2168,6 +2343,7 @@ "ja": "トランペット", "nb_NO": "Trompet", "nl": "Trompet", + "pt": "Trompete", "pt_BR": "Trombeta", "ru": "Труба", "si": null, @@ -2179,7 +2355,8 @@ "tzm": null, "uk": "Труба", "vi": "Kèn", - "zh_Hans": "喇叭" + "zh_Hans": "喇叭", + "zh_Hant": "喇叭" } }, { @@ -2196,6 +2373,7 @@ "eo": "Sonorilo", "es": "Campana", "et": "Kelluke", + "fa": "زنگ", "fi": "Soittokello", "fr": "Cloche", "hr": "zvono", @@ -2205,10 +2383,11 @@ "ja": "ベル", "nb_NO": "Bjelle", "nl": "Bel", + "pt": "Sino", "pt_BR": "Sino", "ru": "Колокол", "si": null, - "sk": "Zvon", + "sk": "Zvonec", "sq": "Kambanë", "sr": "звоно", "sv": "Bjällra", @@ -2216,7 +2395,8 @@ "tzm": null, "uk": "Дзвін", "vi": "Chuông", - "zh_Hans": "铃铛" + "zh_Hans": "铃铛", + "zh_Hant": "鈴鐺" } }, { @@ -2233,6 +2413,7 @@ "eo": "Ankro", "es": "Ancla", "et": "Ankur", + "fa": "لنگر", "fi": "Ankkuri", "fr": "Ancre", "hr": "sidro", @@ -2242,6 +2423,7 @@ "ja": "いかり", "nb_NO": "Anker", "nl": "Anker", + "pt": "Âncora", "pt_BR": "Âncora", "ru": "Якорь", "si": null, @@ -2253,7 +2435,8 @@ "tzm": null, "uk": "Якір", "vi": "Mỏ neo", - "zh_Hans": "锚" + "zh_Hans": "锚", + "zh_Hant": "船錨" } }, { @@ -2270,6 +2453,7 @@ "eo": "Kapaŭdilo", "es": "Cascos", "et": "Kõrvaklapid", + "fa": "هدفون", "fi": "Kuulokkeet", "fr": "Casque audio", "hr": "slušalice", @@ -2279,6 +2463,7 @@ "ja": "ヘッドホン", "nb_NO": "Hodetelefoner", "nl": "Koptelefoon", + "pt": "Fones", "pt_BR": "Fones de ouvido", "ru": "Наушники", "si": null, @@ -2290,7 +2475,8 @@ "tzm": null, "uk": "Навушники", "vi": "Tai nghe", - "zh_Hans": "耳机" + "zh_Hans": "耳机", + "zh_Hant": "耳機" } }, { @@ -2307,15 +2493,17 @@ "eo": "Dosierujo", "es": "Carpeta", "et": "Kaust", + "fa": "پوشه", "fi": "Kansio", "fr": "Dossier", "hr": "mapu", "hu": "Mappa", "id": "Map", "it": "Cartella", - "ja": "フォルダ", + "ja": "フォルダー", "nb_NO": "Mappe", "nl": "Map", + "pt": "Pasta", "pt_BR": "Pasta", "ru": "Папка", "si": null, @@ -2327,7 +2515,8 @@ "tzm": "Asdaw", "uk": "Тека", "vi": "Thư mục", - "zh_Hans": "文件夹" + "zh_Hans": "文件夹", + "zh_Hant": "資料夾" } }, { @@ -2344,6 +2533,7 @@ "eo": "Pinglo", "es": "Alfiler", "et": "Nööpnõel", + "fa": "سنجاق", "fi": "Nuppineula", "fr": "Punaise", "hr": "pribadača", @@ -2353,6 +2543,7 @@ "ja": "ピン", "nb_NO": "Tegnestift", "nl": "Duimspijker", + "pt": "Pionés", "pt_BR": "Alfinete", "ru": "Булавка", "si": null, @@ -2364,7 +2555,8 @@ "tzm": null, "uk": "Кнопка", "vi": "Ghim", - "zh_Hans": "图钉" + "zh_Hans": "图钉", + "zh_Hant": "圖釘" } } ] \ No newline at end of file diff --git a/data/api/application-service/definitions/protocol.yaml b/data/api/application-service/definitions/protocol.yaml index f29d72e8..ff6300db 100644 --- a/data/api/application-service/definitions/protocol.yaml +++ b/data/api/application-service/definitions/protocol.yaml @@ -41,11 +41,10 @@ properties: type: string example: "mxc://example.org/aBcDeFgH" field_types: - title: Field Types description: |- - The type definitions for the fields defined in the `user_fields` and - `location_fields`. Each entry in those arrays MUST have an entry here. The - `string` key for this object is field name itself. + The type definitions for the fields defined in `user_fields` and + `location_fields`. Each entry in those arrays MUST have an entry here. + The `string` key for this object is the field name itself. May be an empty object if no fields are defined. type: object @@ -61,10 +60,9 @@ properties: may apply additional validation or filtering. type: string placeholder: - description: An placeholder serving as a valid example of the field value. + description: A placeholder serving as a valid example of the field value. type: string required: ['regexp', 'placeholder'] - required: ['fieldname'] example: { "network": { "regexp": "([a-z0-9]+\\.)*[a-z0-9]+", diff --git a/data/api/application-service/definitions/registration.yaml b/data/api/application-service/definitions/registration.yaml index d9dfe748..ce702df0 100644 --- a/data/api/application-service/definitions/registration.yaml +++ b/data/api/application-service/definitions/registration.yaml @@ -29,7 +29,16 @@ properties: description: A secret token that the homeserver will use authenticate requests to the application service. sender_localpart: type: string - description: The localpart of the user associated with the application service. + description: |- + The localpart of the user associated with the application service. Events will be sent to the AS if this user is the target of the event, or + is a joined member of the room where the event occurred. + receive_ephemeral: + type: boolean + x-addedInMatrixVersion: "1.13" + description: |- + Whether the application service wants to [receive ephemeral data](/application-service-api/#pushing-ephemeral-data). + + Defaults to `false` if not present. namespaces: type: object title: Namespaces @@ -40,9 +49,10 @@ properties: - $ref: namespace_list.yaml - description: |- A list of namespaces defining the user IDs that the application - service is interested in. Events will be sent to the AS if a - local user matching one of the namespaces is the target of the event, - or is a joined member of the room where the event occurred. + service is interested in, in addition to its `sender_localpart`. + Events will be sent to the AS if a local user matching one of the + namespaces is the target of the event, or is a joined member of + the room where the event occurred. rooms: allOf: - $ref: namespace_list.yaml diff --git a/data/api/application-service/definitions/security.yaml b/data/api/application-service/definitions/security.yaml index b28d033a..b2ba1293 100644 --- a/data/api/application-service/definitions/security.yaml +++ b/data/api/application-service/definitions/security.yaml @@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. homeserverAccessToken: - type: apiKey - name: Authorization - in: header + type: http + scheme: bearer description: The `Bearer` `hs_token` provided by the application service's registration. diff --git a/data/api/application-service/definitions/user.yaml b/data/api/application-service/definitions/user.yaml index 3178b56d..62cac033 100644 --- a/data/api/application-service/definitions/user.yaml +++ b/data/api/application-service/definitions/user.yaml @@ -15,7 +15,7 @@ # TODO: Change userid to user_id as a breaking change properties: userid: - description: A Matrix User ID represting a third-party user. + description: A Matrix User ID representing a third-party user. type: string example: "@_gitter_jim:matrix.org" protocol: diff --git a/data/api/application-service/ping.yaml b/data/api/application-service/ping.yaml index 291f96fa..277955ff 100644 --- a/data/api/application-service/ping.yaml +++ b/data/api/application-service/ping.yaml @@ -69,4 +69,5 @@ servers: default: /_matrix/app/v1 components: securitySchemes: - $ref: definitions/security.yaml + homeserverAccessToken: + $ref: definitions/security.yaml#/homeserverAccessToken diff --git a/data/api/application-service/protocols.yaml b/data/api/application-service/protocols.yaml index dddd26d4..194bdeef 100644 --- a/data/api/application-service/protocols.yaml +++ b/data/api/application-service/protocols.yaml @@ -339,4 +339,5 @@ servers: default: /_matrix/app/v1 components: securitySchemes: - $ref: definitions/security.yaml + homeserverAccessToken: + $ref: definitions/security.yaml#/homeserverAccessToken diff --git a/data/api/application-service/query_room.yaml b/data/api/application-service/query_room.yaml index b5280e39..57175637 100644 --- a/data/api/application-service/query_room.yaml +++ b/data/api/application-service/query_room.yaml @@ -103,4 +103,5 @@ servers: default: /_matrix/app/v1 components: securitySchemes: - $ref: definitions/security.yaml + homeserverAccessToken: + $ref: definitions/security.yaml#/homeserverAccessToken diff --git a/data/api/application-service/query_user.yaml b/data/api/application-service/query_user.yaml index 09503be1..c8ca9781 100644 --- a/data/api/application-service/query_user.yaml +++ b/data/api/application-service/query_user.yaml @@ -100,4 +100,5 @@ servers: default: /_matrix/app/v1 components: securitySchemes: - $ref: definitions/security.yaml + homeserverAccessToken: + $ref: definitions/security.yaml#/homeserverAccessToken diff --git a/data/api/application-service/transactions.yaml b/data/api/application-service/transactions.yaml index 473def4b..29512973 100644 --- a/data/api/application-service/transactions.yaml +++ b/data/api/application-service/transactions.yaml @@ -46,6 +46,15 @@ paths: schema: type: object example: { + "ephemeral": [ + { + "$ref": "../../event-schemas/examples/m.receipt.yaml", + "room_id": "!jEsUZKDJdhlrceRyVU:example.org" + }, + { + "$ref": "../../event-schemas/examples/m.presence.yaml" + }, + ], "events": [ { "$ref": "../../event-schemas/examples/m.room.member.yaml" @@ -61,6 +70,21 @@ paths: description: A list of events, formatted as per the Client-Server API. items: $ref: ../client-server/definitions/client_event.yaml + ephemeral: + type: array + x-addedInMatrixVersion: "1.13" + description: |- + A list of ephemeral data, if the `receive_ephemeral` setting was enabled in the + [registration](/application-service-api/#registration) file. + + There are only three event types that can currently occur in this list: `m.presence`, + `m.typing`, and `m.receipt`. Room-scoped ephemeral data (`m.typing` and + `m.receipt`) MUST include a `room_id` property to identify the room that they + were sent in. + + This property can be omitted if it would be empty. + items: + $ref: ../../event-schemas/schema/core-event-schema/event.yaml required: - events description: Transaction information @@ -88,4 +112,5 @@ servers: default: /_matrix/app/v1 components: securitySchemes: - $ref: definitions/security.yaml + homeserverAccessToken: + $ref: definitions/security.yaml#/homeserverAccessToken diff --git a/data/api/client-server/account-data.yaml b/data/api/client-server/account-data.yaml index bf89b21b..fea15d95 100644 --- a/data/api/client-server/account-data.yaml +++ b/data/api/client-server/account-data.yaml @@ -23,10 +23,11 @@ paths: Set some account data for the client. This config is only visible to the user that set the account data. The config will be available to clients through the top-level `account_data` field in the homeserver response to - [/sync](#get_matrixclientv3sync). + [/sync](/client-server-api/#get_matrixclientv3sync). operationId: setAccountData security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -117,7 +118,8 @@ paths: that set the account data. operationId: getAccountData security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -183,10 +185,11 @@ paths: description: |- Set some account data for the client on a given room. This config is only visible to the user that set the account data. The config will be delivered to - clients in the per-room entries via [/sync](#get_matrixclientv3sync). + clients in the per-room entries via [/sync](/client-server-api/#get_matrixclientv3sync). operationId: setAccountDataPerRoom security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -285,7 +288,8 @@ paths: visible to the user that set the account data. operationId: getAccountDataPerRoom security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -379,4 +383,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/admin.yaml b/data/api/client-server/admin.yaml index ec92eadb..19f084b7 100644 --- a/data/api/client-server/admin.yaml +++ b/data/api/client-server/admin.yaml @@ -27,7 +27,8 @@ paths: specified in this document. operationId: getWhoIs security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -120,4 +121,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/administrative_contact.yaml b/data/api/client-server/administrative_contact.yaml index f2adefd1..eddb2b01 100644 --- a/data/api/client-server/administrative_contact.yaml +++ b/data/api/client-server/administrative_contact.yaml @@ -31,7 +31,8 @@ paths: identifiers that it will accept to reset the user's account password. operationId: getAccount3PIDs security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: The lookup was successful. @@ -101,7 +102,8 @@ paths: operationId: post3PIDs deprecated: true security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -201,7 +203,8 @@ paths: already been added to another user's account on the homeserver. operationId: add3PID security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -263,7 +266,8 @@ paths: Homeservers should track successful binds so they can be unbound later. operationId: bind3PID security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -324,7 +328,8 @@ paths: identity server instead. operationId: delete3pidFromAccount security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -393,7 +398,8 @@ paths: identity server instead. operationId: unbind3pidFromAccount security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -482,9 +488,13 @@ paths: "400": description: |- The third-party identifier is already in use on the homeserver, or - the request was invalid. The error code `M_SERVER_NOT_TRUSTED` - can be returned if the server does not trust/support the identity server - provided in the request. + the request was invalid. Error codes that can be returned are: + * `M_THREEPID_IN_USE`: The email supplied cannot be bound because is is already + associated with a different Matrix ID. + * `M_SERVER_NOT_TRUSTED`: The server does not trust/support the identity server + provided in the request. + * `M_THREEPID_MEDIUM_NOT_SUPPORTED`: The homeserver does not support adding email addresses. + * `M_INVALID_PARAM`: The email address given was not valid. content: application/json: schema: @@ -541,9 +551,12 @@ paths: "400": description: |- The third-party identifier is already in use on the homeserver, or - the request was invalid. The error code `M_SERVER_NOT_TRUSTED` - can be returned if the server does not trust/support the identity server - provided in the request. + the request was invalid. Error codes that can be returned are: + * `M_THREEPID_IN_USE`: The phone number supplied cannot be bound because is is already + associated with a different Matrix ID. + * `M_SERVER_NOT_TRUSTED`: The server does not trust/support the identity server + * `M_THREEPID_MEDIUM_NOT_SUPPORTED`: The homeserver does not support adding phone numbers. + * `M_INVALID_PARAM`: The phone number given was not valid. content: application/json: schema: @@ -584,4 +597,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/appservice_ping.yaml b/data/api/client-server/appservice_ping.yaml index 7102659e..ed84a089 100644 --- a/data/api/client-server/appservice_ping.yaml +++ b/data/api/client-server/appservice_ping.yaml @@ -23,7 +23,7 @@ paths: connection works. description: |- This API asks the homeserver to call the - [`/_matrix/app/v1/ping`](#post_matrixappv1ping) endpoint on the + [`/_matrix/app/v1/ping`](/application-service-api/#post_matrixappv1ping) endpoint on the application service to ensure that the homeserver can communicate with the application service. @@ -57,8 +57,8 @@ paths: example: mautrix-go_1683636478256400935_123 required: true security: - # again, this is the appservice's token - not a typical client's - - accessToken: [] + - appserviceAccessTokenQuery: [] + - appserviceAccessTokenBearer: [] responses: "200": description: The ping was successful. @@ -71,7 +71,7 @@ paths: type: integer description: |- The duration in milliseconds that the - [`/_matrix/app/v1/ping`](#post_matrixappv1ping) + [`/_matrix/app/v1/ping`](/application-service-api/#post_matrixappv1ping) request took from the homeserver's point of view. required: - duration_ms @@ -177,6 +177,7 @@ servers: default: /_matrix/client/v1 components: securitySchemes: - # Note: this is the same access_token definition used elsewhere in the client - # server API, however this expects an access token for an application service. - $ref: definitions/security.yaml + appserviceAccessTokenQuery: + $ref: definitions/security.yaml#/appserviceAccessTokenQuery + appserviceAccessTokenBearer: + $ref: definitions/security.yaml#/appserviceAccessTokenBearer diff --git a/data/api/client-server/appservice_room_directory.yaml b/data/api/client-server/appservice_room_directory.yaml index 2af58a22..b4ec42f0 100644 --- a/data/api/client-server/appservice_room_directory.yaml +++ b/data/api/client-server/appservice_room_directory.yaml @@ -67,8 +67,8 @@ paths: - visibility required: true security: - # again, this is the appservice's token - not a typical client's - - accessToken: [] + - appserviceAccessTokenQuery: [] + - appserviceAccessTokenBearer: [] responses: "200": description: The room's directory visibility has been updated. @@ -95,6 +95,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - # Note: this is the same access_token definition used elsewhere in the client - # server API, however this expects an access token for an application service. - $ref: definitions/security.yaml + appserviceAccessTokenQuery: + $ref: definitions/security.yaml#/appserviceAccessTokenQuery + appserviceAccessTokenBearer: + $ref: definitions/security.yaml#/appserviceAccessTokenBearer diff --git a/data/api/client-server/authed-content-repo.yaml b/data/api/client-server/authed-content-repo.yaml new file mode 100644 index 00000000..53416cf3 --- /dev/null +++ b/data/api/client-server/authed-content-repo.yaml @@ -0,0 +1,586 @@ +# Copyright 2016 OpenMarket Ltd +# Copyright 2019-2024 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +openapi: 3.1.0 +info: + title: Matrix Client-Server (Authenticated) Content Repository API + version: 1.0.0 +paths: + "/media/download/{serverName}/{mediaId}": + get: + x-addedInMatrixVersion: "1.11" + summary: Download content from the content repository. + description: |- + {{% boxes/note %}} + Clients SHOULD NOT generate or use URLs which supply the access token in + the query string. These URLs may be copied by users verbatim and provided + in a chat message to another user, disclosing the sender's access token. + {{% /boxes/note %}} + + Clients MAY be redirected using the 307/308 responses below to download + the request object. This is typical when the homeserver uses a Content + Delivery Network (CDN). + operationId: getContentAuthed + security: + - accessTokenQuery: [] + - accessTokenBearer: [] + parameters: + - $ref: '#/components/parameters/serverName' + - $ref: '#/components/parameters/mediaId' + - $ref: '#/components/parameters/timeout_ms' + responses: + "200": + description: The content that was previously uploaded. + headers: + Content-Type: + $ref: '#/components/headers/downloadContentType' + Content-Disposition: + x-changedInMatrixVersion: + "1.12": This header became required. + description: | + The [disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) + of the returned content. MUST be one of `inline` or `attachment`, + and SHOULD contain a file name. + + If the `Content-Type` is allowed in the [restrictions for serving + inline content](/client-server-api/#serving-inline-content), + servers SHOULD use `inline`, otherwise they SHOULD use + `attachment`. + + If the upload was made with a `filename`, this header MUST + contain the same `filename`. Otherwise, `filename` is excluded + from the header. If the media being downloaded is remote, the + remote server's `filename` in the `Content-Disposition` header + is used as the `filename` instead. When the header is not + supplied, or does not supply a `filename`, the local download + response does not include a `filename`. + required: true + schema: + type: string + example: "inline; filename=\"filename.jpg\"" + content: + application/octet-stream: + schema: + # This is a workaround for us not being able to say the response is required. + description: "**Required.** The bytes for the uploaded file." + "307": + $ref: '#/components/responses/downloadRedirect' + "308": + $ref: '#/components/responses/downloadRedirect' + "429": + $ref: '#/components/responses/rateLimited' + "502": + $ref: '#/components/responses/downloadTooLarge' + "504": + $ref: '#/components/responses/notYetUploaded' + tags: + - Media + "/media/download/{serverName}/{mediaId}/{fileName}": + get: + x-addedInMatrixVersion: "1.11" + summary: Download content from the content repository overriding the file name. + description: |- + This will download content from the content repository (same as + the previous endpoint) but replaces the target file name with the one + provided by the caller. + + {{% boxes/note %}} + Clients SHOULD NOT generate or use URLs which supply the access token in + the query string. These URLs may be copied by users verbatim and provided + in a chat message to another user, disclosing the sender's access token. + {{% /boxes/note %}} + + Clients MAY be redirected using the 307/308 responses below to download + the request object. This is typical when the homeserver uses a Content + Delivery Network (CDN). + operationId: getContentOverrideNameAuthed + security: + - accessTokenQuery: [] + - accessTokenBearer: [] + parameters: + - $ref: '#/components/parameters/serverName' + - $ref: '#/components/parameters/mediaId' + - in: path + name: fileName + required: true + description: A filename to give in the `Content-Disposition` header. + example: filename.jpg + schema: + type: string + - $ref: '#/components/parameters/timeout_ms' + responses: + "200": + description: The content that was previously uploaded. + headers: + Content-Type: + $ref: '#/components/headers/downloadContentType' + Content-Disposition: + x-changedInMatrixVersion: + "1.12": This header became required. + description: | + The [disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) + of the returned content. MUST be one of `inline` or `attachment`, + and MUST contain the file name requested in the path. + + If the `Content-Type` is allowed in the [restrictions for serving + inline content](/client-server-api/#serving-inline-content), + servers SHOULD use `inline`, otherwise they SHOULD use + `attachment`. + required: true + schema: + type: string + example: "inline; filename=\"filename.jpg\"" + content: + application/octet-stream: + schema: + # This is a workaround for us not being able to say the response is required. + description: "**Required.** The bytes for the uploaded file." + "307": + $ref: '#/components/responses/downloadRedirect' + "308": + $ref: '#/components/responses/downloadRedirect' + "429": + $ref: '#/components/responses/rateLimited' + "502": + $ref: '#/components/responses/downloadTooLarge' + "504": + $ref: '#/components/responses/notYetUploaded' + tags: + - Media + "/media/thumbnail/{serverName}/{mediaId}": + get: + x-addedInMatrixVersion: "1.11" + summary: Download a thumbnail of content from the content repository + description: |- + Download a thumbnail of content from the content repository. + See the [Thumbnails](/client-server-api/#thumbnails) section for more information. + + {{% boxes/note %}} + Clients SHOULD NOT generate or use URLs which supply the access token in + the query string. These URLs may be copied by users verbatim and provided + in a chat message to another user, disclosing the sender's access token. + {{% /boxes/note %}} + + Clients MAY be redirected using the 307/308 responses below to download + the request object. This is typical when the homeserver uses a Content + Delivery Network (CDN). + operationId: getContentThumbnailAuthed + security: + - accessTokenQuery: [] + - accessTokenBearer: [] + parameters: + - $ref: '#/components/parameters/serverName' + - $ref: '#/components/parameters/mediaId' + - in: query + name: width + required: true + description: |- + The *desired* width of the thumbnail. The actual thumbnail may be + larger than the size specified. + example: 64 + schema: + type: integer + - in: query + name: height + required: true + description: |- + The *desired* height of the thumbnail. The actual thumbnail may be + larger than the size specified. + example: 64 + schema: + type: integer + - in: query + name: method + description: |- + The desired resizing method. See the [Thumbnails](/client-server-api/#thumbnails) + section for more information. + example: scale + schema: + type: string + enum: + - crop + - scale + - $ref: '#/components/parameters/timeout_ms' + - in: query + name: animated + x-addedInMatrixVersion: "1.11" + required: false + description: | + Indicates preference for an animated thumbnail from the server, if possible. Animated + thumbnails typically use the content types `image/gif`, `image/png` (with APNG format), + `image/apng`, and `image/webp` instead of the common static `image/png` or `image/jpeg` + content types. + + When `true`, the server SHOULD return an animated thumbnail if possible and supported. + When `false`, the server MUST NOT return an animated thumbnail. For example, returning a + static `image/png` or `image/jpeg` thumbnail. When not provided, the server SHOULD NOT + return an animated thumbnail. + + Servers SHOULD prefer to return `image/webp` thumbnails when supporting animation. + + When `true` and the media cannot be animated, such as in the case of a JPEG or PDF, the + server SHOULD behave as though `animated` is `false`. + example: false + schema: + type: boolean + responses: + "200": + description: A thumbnail of the requested content. + headers: + Content-Disposition: + x-addedInMatrixVersion: "1.12" + description: | + The [disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) + of the returned content. MUST be `inline`, and SHOULD contain a file name (e.g. `thumbnail.png`). + + Servers should note the [Content-Type restrictions for serving inline content](/client-server-api/#serving-inline-content), + as these limitations imply which formats should be used for thumbnail generation. + required: true + schema: + type: string + example: "inline; filename=\"thumbnail.png\"" + Content-Type: + x-changedInMatrixVersion: + "1.12": | + This header became required in order to support `Content-Disposition`. + description: The content type of the thumbnail. + required: true + schema: + type: string + enum: + - image/jpeg + - image/png + - image/apng + - image/gif + - image/webp + content: + image/jpeg: + schema: + # This is a workaround for us not being able to say the response is required. + description: "**Required.** The bytes for the thumbnail." + image/png: + schema: + x-changedInMatrixVersion: + "1.11": The PNG may be of the APNG variety if animation is supported and requested. + description: | + **Required.** The bytes for the thumbnail. The thumbnail MAY use an animated + format if `animated=true`. + image/apng: + schema: + x-addedInMatrixVersion: "1.11" + description: "**Required.** The bytes for the *animated* thumbnail." + image/gif: + schema: + x-addedInMatrixVersion: "1.11" + description: "**Required.** The bytes for the *animated* thumbnail." + image/webp: + schema: + x-addedInMatrixVersion: "1.11" + description: "**Required.** The bytes for the *animated* thumbnail." + "307": + $ref: '#/components/responses/thumbnailRedirect' + "308": + $ref: '#/components/responses/thumbnailRedirect' + "400": + description: |- + The request does not make sense to the server, or the server cannot thumbnail + the content. For example, the client requested non-integer dimensions or asked + for negatively-sized images. + content: + application/json: + schema: + $ref: definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_UNKNOWN", + "error": "Cannot generate thumbnails for the requested content" + } + "413": + description: The local content is too large for the server to thumbnail. + content: + application/json: + schema: + $ref: definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_TOO_LARGE", + "error": "Content is too large to thumbnail" + } + "429": + $ref: '#/components/responses/rateLimited' + "502": + description: The remote content is too large for the server to thumbnail. + content: + application/json: + schema: + $ref: definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_TOO_LARGE", + "error": "Content is too large to thumbnail" + } + "504": + $ref: '#/components/responses/notYetUploaded' + tags: + - Media + /media/preview_url: + get: + x-addedInMatrixVersion: "1.11" + summary: Get information about a URL for a client + description: |- + Get information about a URL for the client. Typically this is called when a + client sees a URL in a message and wants to render a preview for the user. + + {{% boxes/note %}} + Clients should consider avoiding this endpoint for URLs posted in encrypted + rooms. Encrypted rooms often contain more sensitive information the users + do not want to share with the homeserver, and this can mean that the URLs + being shared should also not be shared with the homeserver. + {{% /boxes/note %}} + operationId: getUrlPreviewAuthed + security: + - accessTokenQuery: [] + - accessTokenBearer: [] + parameters: + - in: query + name: url + description: The URL to get a preview of. + required: true + example: https://matrix.org + schema: + type: string + format: uri + - in: query + name: ts + description: |- + The preferred point in time to return a preview for. The server may + return a newer version if it does not have the requested version + available. + example: 1510610716656 + schema: + type: integer + format: int64 + responses: + "200": + description: |- + The OpenGraph data for the URL, which may be empty. Some values are + replaced with matrix equivalents if they are provided in the response. + The differences from the OpenGraph protocol are described here. + content: + application/json: + schema: + type: object + properties: + matrix:image:size: + type: integer + format: int64 + description: The byte-size of the image. Omitted if there is no image attached. + og:image: + type: string + format: uri + description: An [`mxc://` URI](/client-server-api/#matrix-content-mxc-uris) to + the image. Omitted if there is no image. + examples: + response: + value: { + "og:title": "Matrix Blog Post", + "og:description": "This is a really cool blog post from matrix.org", + "og:image": "mxc://example.com/ascERGshawAWawugaAcauga", + "og:image:type": "image/png", + "og:image:height": 48, + "og:image:width": 48, + "matrix:image:size": 102400 + } + "429": + $ref: '#/components/responses/rateLimited' + tags: + - Media + /media/config: + get: + x-addedInMatrixVersion: "1.11" + summary: Get the configuration for the content repository. + description: |- + This endpoint allows clients to retrieve the configuration of the content + repository, such as upload limitations. + Clients SHOULD use this as a guide when using content repository endpoints. + All values are intentionally left optional. Clients SHOULD follow + the advice given in the field description when the field is not available. + + {{% boxes/note %}} + Both clients and server administrators should be aware that proxies + between the client and the server may affect the apparent behaviour of content + repository APIs, for example, proxies may enforce a lower upload size limit + than is advertised by the server on this endpoint. + {{% /boxes/note %}} + operationId: getConfigAuthed + security: + - accessTokenQuery: [] + - accessTokenBearer: [] + responses: + "200": + description: The public content repository configuration for the matrix server. + content: + application/json: + schema: + type: object + properties: + m.upload.size: + type: integer + format: int64 + description: |- + The maximum size an upload can be in bytes. + Clients SHOULD use this as a guide when uploading content. + If not listed or null, the size limit should be treated as unknown. + examples: + response: + value: { + "m.upload.size": 50000000 + } + "429": + $ref: '#/components/responses/rateLimited' + tags: + - Media +servers: + - url: "{protocol}://{hostname}{basePath}" + variables: + protocol: + enum: + - http + - https + default: https + hostname: + default: localhost:8008 + basePath: + default: /_matrix/client/v1 +components: + securitySchemes: + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer + parameters: + serverName: + in: path + name: serverName + required: true + description: | + The server name from the `mxc://` URI (the authority component). + example: matrix.org + schema: + type: string + format: mx-server-name + mediaId: + in: path + name: mediaId + required: true + description: | + The media ID from the `mxc://` URI (the path component). + example: ascERGshawAWawugaAcauga + schema: + type: string + timeout_ms: + in: query + name: timeout_ms + x-addedInMatrixVersion: "1.7" + description: | + The maximum number of milliseconds that the client is willing to wait to + start receiving data, in the case that the content has not yet been + uploaded. The default value is 20000 (20 seconds). The content + repository SHOULD impose a maximum value for this parameter. The + content repository MAY respond before the timeout. + example: 5000 + schema: + type: integer + format: int64 + default: 20000 + responses: + rateLimited: + description: This request was rate-limited. + content: + application/json: + schema: + $ref: definitions/errors/rate_limited.yaml + notYetUploaded: + description: |- + The content is not yet available. A [standard error response](/client-server-api/#standard-error-response) + will be returned with the `errcode` `M_NOT_YET_UPLOADED`. + content: + application/json: + schema: + $ref: definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_NOT_YET_UPLOADED", + "error": "Content has not yet been uploaded" + } + downloadRedirect: + description: A redirect to the requested content. + headers: + Location: + description: The URL of the content. + schema: + type: string + format: uri + downloadTooLarge: + description: The content is too large for the server to serve. + content: + application/json: + schema: + $ref: definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_TOO_LARGE", + "error": "Content is too large to serve" + } + thumbnailRedirect: + description: A redirect to the thumbnail of the requested content. + headers: + Location: + description: The URL of the thumbnail content. + schema: + type: string + format: uri + headers: + downloadContentType: + description: | + The content type of the file that was previously uploaded. + + The server MUST return a `Content-Type` which is either exactly the same + as the original upload, or reasonably close. The bounds of "reasonable" + are: + + * Adding a charset to `text/*` content types. + * Detecting HTML and using `text/html` instead of `text/plain`. + * Using `application/octet-stream` when the server determines the + content type is obviously wrong. For example, an encrypted file being + claimed as `image/png`. + * Returning `application/octet-stream` when the media has an + unknown/unprovided `Content-Type`. For example, being uploaded before + the server tracked content types or when the remote server is + non-compliantly omitting the header entirely. + + Actions not in the spirit of the above are not considered "reasonable". + x-changedInMatrixVersion: + "1.12": | + This header became required in order to support `Content-Disposition`, + and the behaviour to compute its value was clarified. + required: true + schema: + type: string + diff --git a/data/api/client-server/banning.yaml b/data/api/client-server/banning.yaml index 5185d89b..3cb9a540 100644 --- a/data/api/client-server/banning.yaml +++ b/data/api/client-server/banning.yaml @@ -27,7 +27,8 @@ paths: The caller must have the required power level in order to perform this operation. operationId: ban security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -96,7 +97,8 @@ paths: The caller must have the required power level in order to perform this operation. operationId: unban security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -169,4 +171,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/capabilities.yaml b/data/api/client-server/capabilities.yaml index 96fdfb56..523c6091 100644 --- a/data/api/client-server/capabilities.yaml +++ b/data/api/client-server/capabilities.yaml @@ -24,7 +24,8 @@ paths: and other relevant capabilities. operationId: getCapabilities security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: The capabilities of the server. @@ -42,19 +43,13 @@ paths: The custom capabilities the server supports, using the Java package naming convention. additionalProperties: - type: object + description: |- + Application-dependent keys using the + [Common Namespaced Identifier Grammar](/appendices/#common-namespaced-identifier-grammar). properties: m.change_password: - type: object + $ref: '#/components/schemas/booleanCapability' description: Capability to indicate if the user can change their password. - title: ChangePasswordCapability - properties: - enabled: - type: boolean - description: True if the user can change their password, false otherwise. - example: false - required: - - enabled m.room_versions: type: object description: The room versions the server supports. @@ -77,6 +72,20 @@ paths: required: - default - available + m.set_displayname: + $ref: '#/components/schemas/booleanCapability' + description: Capability to indicate if the user can change their display name. + m.set_avatar_url: + $ref: '#/components/schemas/booleanCapability' + description: Capability to indicate if the user can change their avatar. + m.3pid_changes: + $ref: '#/components/schemas/booleanCapability' + description: Capability to indicate if the user can change 3PID associations + on their account. + m.get_login_token: + $ref: '#/components/schemas/booleanCapability' + description: Capability to indicate if the user can generate tokens to log further + clients into their account. examples: response: value: { @@ -120,4 +129,18 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer + schemas: + booleanCapability: + type: object + title: BooleanCapability + properties: + enabled: + type: boolean + description: True if the user can perform the action, false otherwise. + example: false + required: + - enabled diff --git a/data/api/client-server/content-repo.yaml b/data/api/client-server/content-repo.yaml index c8800279..c64a914b 100644 --- a/data/api/client-server/content-repo.yaml +++ b/data/api/client-server/content-repo.yaml @@ -22,26 +22,13 @@ paths: summary: Upload some content to the content repository. operationId: uploadContent security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - - in: header - name: Content-Type - description: The content type of the file being uploaded - example: application/pdf - schema: - type: string - - in: query - name: filename - description: The name of the file being uploaded - example: War and Peace.pdf - schema: - type: string + - $ref: '#/components/parameters/contentType' + - $ref: '#/components/parameters/filename' requestBody: - content: - application/octet-stream: - example: - description: The content to be uploaded. - required: true + $ref: '#/components/requestBodies/bytes' responses: "200": description: The [`mxc://` URI](/client-server-api/#matrix-content-mxc-uris) for @@ -55,7 +42,8 @@ paths: properties: content_uri: type: string - format: uri + format: mx-mxc-uri + pattern: "^mxc:\\/\\/" description: The [`mxc://` URI](/client-server-api/#matrix-content-mxc-uris) to the uploaded content. examples: @@ -80,23 +68,9 @@ paths: "error": "Cannot upload this content" } "413": - description: The uploaded content is too large for the server. - content: - application/json: - schema: - $ref: definitions/errors/error.yaml - examples: - response: - value: { - "errcode": "M_TOO_LARGE", - "error": "Cannot upload files larger than 100mb" - } + $ref: '#/components/responses/uploadTooLarge' "429": - description: This request was rate-limited. - content: - application/json: - schema: - $ref: definitions/errors/rate_limited.yaml + $ref: '#/components/responses/rateLimited' tags: - Media "/media/v3/upload/{serverName}/{mediaId}": @@ -107,41 +81,20 @@ paths: earlier via [POST /_matrix/media/v1/create](/client-server-api/#post_matrixmediav1create). operationId: uploadContentToMXC x-addedInMatrixVersion: "1.7" + security: + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - - in: path - name: serverName - required: true + - $ref: '#/components/parameters/serverName' description: | - The server name from the `mxc://` URI returned by `POST /_matrix/media/v1/create` (the authoritory component). - example: matrix.org - schema: - type: string - - in: path - name: mediaId - required: true + The server name from the `mxc://` URI returned by `POST /_matrix/media/v1/create` (the authority component). + - $ref: '#/components/parameters/mediaId' description: | The media ID from the `mxc://` URI returned by `POST /_matrix/media/v1/create` (the path component). - example: ascERGshawAWawugaAcauga - schema: - type: string - - in: header - name: Content-Type - description: The content type of the file being uploaded - example: application/pdf - schema: - type: string - - in: query - name: filename - description: The name of the file being uploaded - example: War and Peace.pdf - schema: - type: string + - $ref: '#/components/parameters/contentType' + - $ref: '#/components/parameters/filename' requestBody: - content: - application/octet-stream: - example: - description: The content to be uploaded. - required: true + $ref: '#/components/requestBodies/bytes' responses: "200": description: The upload was successful. @@ -173,6 +126,25 @@ paths: "errcode": "M_FORBIDDEN", "error": "Cannot upload this content" } + "404": + description: |- + The user has provided an invalid MXC ID. Some reasons for this error include: + + - The MXC ID was not created with [POST /_matrix/media/v1/create](/client-server-api/#post_matrixmediav1create). + - The MXC ID has expired. + + A [standard error response](/client-server-api/#standard-error-response) + will be returned with the `errcode` `M_NOT_FOUND`. + content: + application/json: + schema: + $ref: definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_NOT_FOUND", + "error": "Unknown media ID" + } "409": description: |- The endpoint was called with a media ID that already has content. A @@ -189,23 +161,9 @@ paths: "error": "Media already uploaded" } "413": - description: The uploaded content is too large for the server. - content: - application/json: - schema: - $ref: definitions/errors/error.yaml - examples: - response: - value: { - "errcode": "M_TOO_LARGE", - "error": "Cannot upload files larger than 100mb" - } + $ref: '#/components/responses/uploadTooLarge' "429": - description: This request was rate-limited. - content: - application/json: - schema: - $ref: definitions/errors/rate_limited.yaml + $ref: '#/components/responses/rateLimited' tags: - Media /media/v1/create: @@ -234,7 +192,8 @@ paths: operationId: createContent x-addedInMatrixVersion: "1.7" security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] # empty json object responses: "200": @@ -249,7 +208,8 @@ paths: properties: content_uri: type: string - format: uri + format: mx-mxc-uri + pattern: "^mxc:\\/\\/" description: |- The [`mxc://` URI](/client-server-api/#matrix-content-mxc-uris) at which the content will be available, once it is uploaded. @@ -274,162 +234,103 @@ paths: "error": "Cannot upload this content" } "429": - description: This request was rate-limited. - content: - application/json: - schema: - $ref: definitions/errors/rate_limited.yaml + $ref: '#/components/responses/rateLimited' tags: - Media "/media/v3/download/{serverName}/{mediaId}": get: + deprecated: true summary: Download content from the content repository. + description: |- + {{% boxes/note %}} + Replaced by [`GET /_matrix/client/v1/media/download/{serverName}/{mediaId}`](/client-server-api/#get_matrixclientv1mediadownloadservernamemediaid) + (requires authentication). + {{% /boxes/note %}} + + {{% boxes/warning %}} + {{% changed-in v="1.11" %}} This endpoint MAY return `404 M_NOT_FOUND` + for media which exists, but is after the server froze unauthenticated + media access. See [Client Behaviour](/client-server-api/#content-repo-client-behaviour) for more + information. + {{% /boxes/warning %}} operationId: getContent parameters: - - in: path - name: serverName - required: true - description: | - The server name from the `mxc://` URI (the authoritory component) - example: matrix.org - schema: - type: string - - in: path - name: mediaId - required: true - description: | - The media ID from the `mxc://` URI (the path component) - example: ascERGshawAWawugaAcauga - schema: - type: string - - in: query - name: allow_remote - required: false - description: | - Indicates to the server that it should not attempt to fetch the media if it is deemed - remote. This is to prevent routing loops where the server contacts itself. Defaults to - true if not provided. - example: false - schema: - type: boolean - default: true - - in: query - name: timeout_ms - x-addedInMatrixVersion: "1.7" - description: | - The maximum number of milliseconds that the client is willing to - wait to start receiving data, in the case that the content has not - yet been uploaded. The default value is 20000 (20 seconds). The - content repository can and should impose a maximum value for this - parameter. The content repository may also choose to respond before - the timeout. - example: 5000 - schema: - type: integer - format: int64 - default: 20000 - - in: query - name: allow_redirect - x-addedInMatrixVersion: "1.7" - required: false - description: | - Indicates to the server that it may return a 307 or 308 redirect response that points - at the relevant media content. When not explicitly set to true the server must return - the media content itself. - example: false - schema: - type: boolean - default: false + - $ref: '#/components/parameters/serverName' + - $ref: '#/components/parameters/mediaId' + - $ref: '#/components/parameters/allow_remote' + - $ref: '#/components/parameters/timeout_ms' + - $ref: '#/components/parameters/allow_redirect' responses: "200": description: The content that was previously uploaded. headers: Content-Type: - description: The content type of the file that was previously uploaded. - schema: - type: string + $ref: '#/components/headers/downloadContentType' Content-Disposition: - description: The name of the file that was previously uploaded, if set. + x-changedInMatrixVersion: + "1.12": This header became required. + description: | + The [disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) + of the returned content. MUST be one of `inline` or `attachment`, + and SHOULD contain a file name. + + If the `Content-Type` is allowed in the [restrictions for serving + inline content](/client-server-api/#serving-inline-content), + servers SHOULD use `inline`, otherwise they SHOULD use + `attachment`. + + If the upload was made with a `filename`, this header MUST + contain the same `filename`. Otherwise, `filename` is excluded + from the header. If the media being downloaded is remote, the + remote server's `filename` in the `Content-Disposition` header + is used as the `filename` instead. When the header is not + supplied, or does not supply a `filename`, the local download + response does not include a `filename`. + required: true schema: type: string + example: "inline; filename=\"filename.jpg\"" content: application/octet-stream: schema: # This is a workaround for us not being able to say the response is required. description: "**Required.** The bytes for the uploaded file." "307": - description: A redirect to the thumbnail of the requested content. - headers: - Location: - description: The URL of the thumbnail content. - schema: - type: string + $ref: '#/components/responses/downloadRedirect' "308": - description: A redirect to the thumbnail of the requested content. - headers: - Location: - description: The URL of the thumbnail content. - schema: - type: string + $ref: '#/components/responses/downloadRedirect' "429": - description: This request was rate-limited. - content: - application/json: - schema: - $ref: definitions/errors/rate_limited.yaml + $ref: '#/components/responses/rateLimited' "502": - description: The content is too large for the server to serve. - content: - application/json: - schema: - $ref: definitions/errors/error.yaml - examples: - response: - value: { - "errcode": "M_TOO_LARGE", - "error": "Content is too large to serve" - } + $ref: '#/components/responses/downloadTooLarge' "504": - description: |- - The content is not yet available. A [standard error response](/client-server-api/#standard-error-response) - will be returned with the `errcode` `M_NOT_YET_UPLOADED`. - content: - application/json: - schema: - $ref: definitions/errors/error.yaml - examples: - response: - value: { - "errcode": "M_NOT_YET_UPLOADED", - "error": "Content has not yet been uploaded" - } + $ref: '#/components/responses/notYetUploaded' tags: - Media "/media/v3/download/{serverName}/{mediaId}/{fileName}": get: + deprecated: true summary: Download content from the content repository overriding the file name description: |- + {{% boxes/note %}} + Replaced by [`GET /_matrix/client/v1/media/download/{serverName}/{mediaId}/{fileName}`](/client-server-api/#get_matrixclientv1mediadownloadservernamemediaidfilename) + (requires authentication). + {{% /boxes/note %}} + This will download content from the content repository (same as the previous endpoint) but replace the target file name with the one provided by the caller. + + {{% boxes/warning %}} + {{% changed-in v="1.11" %}} This endpoint MAY return `404 M_NOT_FOUND` + for media which exists, but is after the server froze unauthenticated + media access. See [Client Behaviour](/client-server-api/#content-repo-client-behaviour) for more + information. + {{% /boxes/warning %}} operationId: getContentOverrideName parameters: - - in: path - name: serverName - required: true - description: | - The server name from the `mxc://` URI (the authoritory component) - example: matrix.org - schema: - type: string - - in: path - name: mediaId - required: true - description: | - The media ID from the `mxc://` URI (the path component) - example: ascERGshawAWawugaAcauga - schema: - type: string + - $ref: '#/components/parameters/serverName' + - $ref: '#/components/parameters/mediaId' - in: path name: fileName required: true @@ -437,135 +338,71 @@ paths: example: filename.jpg schema: type: string - - in: query - name: allow_remote - required: false - description: | - Indicates to the server that it should not attempt to fetch the media if it is deemed - remote. This is to prevent routing loops where the server contacts itself. Defaults to - true if not provided. - example: false - schema: - type: boolean - default: true - - in: query - name: timeout_ms - x-addedInMatrixVersion: "1.7" - description: | - The maximum number of milliseconds that the client is willing to - wait to start receiving data, in the case that the content has not - yet been uploaded. The default value is 20000 (20 seconds). The - content repository can and should impose a maximum value for this - parameter. The content repository may also choose to respond before - the timeout. - example: 5000 - schema: - type: integer - format: int64 - default: 20000 - - in: query - name: allow_redirect - x-addedInMatrixVersion: "1.7" - required: false - description: | - Indicates to the server that it may return a 307 or 308 redirect response that points - at the relevant media content. When not explicitly set to true the server must return - the media content itself. - example: false - schema: - type: boolean - default: false + - $ref: '#/components/parameters/allow_remote' + - $ref: '#/components/parameters/timeout_ms' + - $ref: '#/components/parameters/allow_redirect' responses: "200": description: The content that was previously uploaded. headers: Content-Type: - description: The content type of the file that was previously uploaded. - schema: - type: string + $ref: '#/components/headers/downloadContentType' Content-Disposition: - description: |- - The `fileName` requested or the name of the file that was previously - uploaded, if set. + x-changedInMatrixVersion: + "1.12": This header became required. + description: | + The [disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) + of the returned content. MUST be one of `inline` or `attachment`, + and MUST contain the file name requested in the path. + + If the `Content-Type` is allowed in the [restrictions for serving + inline content](/client-server-api/#serving-inline-content), + servers SHOULD use `inline`, otherwise they SHOULD use + `attachment`. + required: true schema: type: string + example: "inline; filename=\"filename.jpg\"" content: application/octet-stream: schema: # This is a workaround for us not being able to say the response is required. description: "**Required.** The bytes for the uploaded file." "307": - description: A redirect to the thumbnail of the requested content. - headers: - Location: - description: The URL of the thumbnail content. - schema: - type: string + $ref: '#/components/responses/downloadRedirect' "308": - description: A redirect to the thumbnail of the requested content. - headers: - Location: - description: The URL of the thumbnail content. - schema: - type: string + $ref: '#/components/responses/downloadRedirect' "429": - description: This request was rate-limited. - content: - application/json: - schema: - $ref: definitions/errors/rate_limited.yaml + $ref: '#/components/responses/rateLimited' "502": - description: The content is too large for the server to serve. - content: - application/json: - schema: - $ref: definitions/errors/error.yaml - examples: - response: - value: { - "errcode": "M_TOO_LARGE", - "error": "Content is too large to serve" - } + $ref: '#/components/responses/downloadTooLarge' "504": - description: |- - The content is not yet available. A [standard error response](/client-server-api/#standard-error-response) - will be returned with the `errcode` `M_NOT_YET_UPLOADED`. - content: - application/json: - schema: - $ref: definitions/errors/error.yaml - examples: - response: - value: { - "errcode": "M_NOT_YET_UPLOADED", - "error": "Content has not yet been uploaded" - } + $ref: '#/components/responses/notYetUploaded' tags: - Media "/media/v3/thumbnail/{serverName}/{mediaId}": get: + deprecated: true summary: Download a thumbnail of content from the content repository description: |- + {{% boxes/note %}} + Replaced by [`GET /_matrix/client/v1/media/thumbnail/{serverName}/{mediaId}`](/client-server-api/#get_matrixclientv1mediathumbnailservernamemediaid) + (requires authentication). + {{% /boxes/note %}} + Download a thumbnail of content from the content repository. See the [Thumbnails](/client-server-api/#thumbnails) section for more information. + + {{% boxes/warning %}} + {{% changed-in v="1.11" %}} This endpoint MAY return `404 M_NOT_FOUND` + for media which exists, but is after the server froze unauthenticated + media access. See [Client Behaviour](/client-server-api/#content-repo-client-behaviour) for more + information. + {{% /boxes/warning %}} operationId: getContentThumbnail parameters: - - in: path - name: serverName - required: true - description: | - The server name from the `mxc://` URI (the authoritory component) - example: example.org - schema: - type: string - - in: path - name: mediaId - required: true - description: | - The media ID from the `mxc://` URI (the path component) - example: ascERGshawAWawugaAcauga - schema: - type: string + - $ref: '#/components/parameters/serverName' + - $ref: '#/components/parameters/mediaId' - in: query name: width required: true @@ -595,55 +432,61 @@ paths: enum: - crop - scale + - $ref: '#/components/parameters/allow_remote' + - $ref: '#/components/parameters/timeout_ms' + - $ref: '#/components/parameters/allow_redirect' - in: query - name: allow_remote + name: animated + x-addedInMatrixVersion: "1.11" required: false - description: |- - Indicates to the server that it should not attempt to fetch - the media if it is deemed remote. This is to prevent routing loops - where the server contacts itself. Defaults to true if not provided. + description: | + Indicates preference for an animated thumbnail from the server, if possible. Animated + thumbnails typically use the content types `image/gif`, `image/png` (with APNG format), + `image/apng`, and `image/webp` instead of the common static `image/png` or `image/jpeg` + content types. + + When `true`, the server SHOULD return an animated thumbnail if possible and supported. + When `false`, the server MUST NOT return an animated thumbnail. For example, returning a + static `image/png` or `image/jpeg` thumbnail. When not provided, the server SHOULD NOT + return an animated thumbnail. + + Servers SHOULD prefer to return `image/webp` thumbnails when supporting animation. + + When `true` and the media cannot be animated, such as in the case of a JPEG or PDF, the + server SHOULD behave as though `animated` is `false`. example: false schema: type: boolean - default: true - - in: query - name: timeout_ms - x-addedInMatrixVersion: "1.7" - description: | - The maximum number of milliseconds that the client is willing to - wait to start receiving data, in the case that the content has not - yet been uploaded. The default value is 20000 (20 seconds). The - content repository can and should impose a maximum value for this - parameter. The content repository may also choose to respond before - the timeout. - example: 5000 - schema: - type: integer - format: int64 - default: 20000 - - in: query - name: allow_redirect - x-addedInMatrixVersion: "1.7" - required: false - description: | - Indicates to the server that it may return a 307 or 308 redirect response that points - at the relevant media content. When not explicitly set to true the server must return - the media content itself. - example: false - schema: - type: boolean - default: false responses: "200": description: A thumbnail of the requested content. headers: + Content-Disposition: + x-addedInMatrixVersion: "1.12" + description: | + The [disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) + of the returned content. MUST be `inline`, and SHOULD contain a file name (e.g. `thumbnail.png`). + + Servers should note the [Content-Type restrictions for serving inline content](/client-server-api/#serving-inline-content), + as these limitations imply which formats should be used for thumbnail generation. + required: true + schema: + type: string + example: "inline; filename=\"thumbnail.png\"" Content-Type: + x-changedInMatrixVersion: + "1.12": | + This header became required in order to support `Content-Disposition`. description: The content type of the thumbnail. + required: true schema: type: string enum: - image/jpeg - image/png + - image/apng + - image/gif + - image/webp content: image/jpeg: schema: @@ -651,21 +494,27 @@ paths: description: "**Required.** The bytes for the thumbnail." image/png: schema: - description: "**Required.** The bytes for the thumbnail." + x-changedInMatrixVersion: + "1.11": The PNG may be of the APNG variety if animation is supported and requested. + description: | + **Required.** The bytes for the thumbnail. The thumbnail MAY use an animated + format if `animated=true`. + image/apng: + schema: + x-addedInMatrixVersion: "1.11" + description: "**Required.** The bytes for the *animated* thumbnail." + image/gif: + schema: + x-addedInMatrixVersion: "1.11" + description: "**Required.** The bytes for the *animated* thumbnail." + image/webp: + schema: + x-addedInMatrixVersion: "1.11" + description: "**Required.** The bytes for the *animated* thumbnail." "307": - description: A redirect to the thumbnail of the requested content. - headers: - Location: - description: The URL of the thumbnail content. - schema: - type: string + $ref: '#/components/responses/thumbnailRedirect' "308": - description: A redirect to the thumbnail of the requested content. - headers: - Location: - description: The URL of the thumbnail content. - schema: - type: string + $ref: '#/components/responses/thumbnailRedirect' "400": description: |- The request does not make sense to the server, or the server cannot thumbnail @@ -694,11 +543,7 @@ paths: "error": "Content is too large to thumbnail" } "429": - description: This request was rate-limited. - content: - application/json: - schema: - $ref: definitions/errors/rate_limited.yaml + $ref: '#/components/responses/rateLimited' "502": description: The remote content is too large for the server to thumbnail. content: @@ -712,25 +557,18 @@ paths: "error": "Content is too large to thumbnail" } "504": - description: |- - The content is not yet available. A [standard error response](/client-server-api/#standard-error-response) - will be returned with the `errcode` `M_NOT_YET_UPLOADED`. - content: - application/json: - schema: - $ref: definitions/errors/error.yaml - examples: - response: - value: { - "errcode": "M_NOT_YET_UPLOADED", - "error": "Content has not yet been uploaded" - } + $ref: '#/components/responses/notYetUploaded' tags: - Media /media/v3/preview_url: get: + deprecated: true summary: Get information about a URL for a client description: |- + {{% boxes/note %}} + Replaced by [`GET /_matrix/client/v1/media/preview_url`](/client-server-api/#get_matrixclientv1mediapreview_url). + {{% /boxes/note %}} + Get information about a URL for the client. Typically this is called when a client sees a URL in a message and wants to render a preview for the user. @@ -741,7 +579,8 @@ paths: being shared should also not be shared with the homeserver. operationId: getUrlPreview security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: url @@ -793,17 +632,18 @@ paths: "matrix:image:size": 102400 } "429": - description: This request was rate-limited. - content: - application/json: - schema: - $ref: definitions/errors/rate_limited.yaml + $ref: '#/components/responses/rateLimited' tags: - Media /media/v3/config: get: + deprecated: true summary: Get the configuration for the content repository. description: |- + {{% boxes/note %}} + Replaced by [`GET /_matrix/client/v1/media/config`](/client-server-api/#get_matrixclientv1mediaconfig). + {{% /boxes/note %}} + This endpoint allows clients to retrieve the configuration of the content repository, such as upload limitations. Clients SHOULD use this as a guide when using content repository endpoints. @@ -816,7 +656,8 @@ paths: than is advertised by the server on this endpoint. operationId: getConfig security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: The public content repository configuration for the matrix server. @@ -838,11 +679,7 @@ paths: "m.upload.size": 50000000 } "429": - description: This request was rate-limited. - content: - application/json: - schema: - $ref: definitions/errors/error.yaml + $ref: '#/components/responses/rateLimited' tags: - Media servers: @@ -859,4 +696,188 @@ servers: default: /_matrix components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer + parameters: + contentType: + in: header + name: Content-Type + description: | + **Optional.** The content type of the file being uploaded. + + Clients SHOULD always supply this header. + + Defaults to `application/octet-stream` if it is not set. + x-changedInMatrixVersion: + "1.12": | + This header became explicitly optional with a default value. + example: application/pdf + schema: + type: string + filename: + in: query + name: filename + description: The name of the file being uploaded + example: War and Peace.pdf + schema: + type: string + serverName: + in: path + name: serverName + required: true + description: | + The server name from the `mxc://` URI (the authority component). + example: matrix.org + schema: + type: string + format: mx-server-name + mediaId: + in: path + name: mediaId + required: true + description: | + The media ID from the `mxc://` URI (the path component). + example: ascERGshawAWawugaAcauga + schema: + type: string + allow_remote: + in: query + name: allow_remote + required: false + description: |- + Indicates to the server that it should not attempt to fetch the media if + it is deemed remote. This is to prevent routing loops where the server + contacts itself. + + Defaults to `true` if not provided. + example: false + schema: + type: boolean + default: true + timeout_ms: + in: query + name: timeout_ms + x-addedInMatrixVersion: "1.7" + description: | + The maximum number of milliseconds that the client is willing to wait to + start receiving data, in the case that the content has not yet been + uploaded. The default value is 20000 (20 seconds). The content + repository SHOULD impose a maximum value for this parameter. The + content repository MAY respond before the timeout. + example: 5000 + schema: + type: integer + format: int64 + default: 20000 + allow_redirect: + in: query + name: allow_redirect + x-addedInMatrixVersion: "1.7" + required: false + description: | + Indicates to the server that it may return a 307 or 308 redirect + response that points at the relevant media content. When not explicitly + set to `true` the server must return the media content itself. + example: false + schema: + type: boolean + default: false + requestBodies: + bytes: + content: + application/octet-stream: + schema: + description: The content to be uploaded. + example: + required: true + responses: + uploadTooLarge: + description: The uploaded content is too large for the server. + content: + application/json: + schema: + $ref: definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_TOO_LARGE", + "error": "Cannot upload files larger than 100mb" + } + rateLimited: + description: This request was rate-limited. + content: + application/json: + schema: + $ref: definitions/errors/rate_limited.yaml + notYetUploaded: + description: |- + The content is not yet available. A [standard error response](/client-server-api/#standard-error-response) + will be returned with the `errcode` `M_NOT_YET_UPLOADED`. + content: + application/json: + schema: + $ref: definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_NOT_YET_UPLOADED", + "error": "Content has not yet been uploaded" + } + downloadRedirect: + description: A redirect to the requested content. + headers: + Location: + description: The URL of the content. + schema: + type: string + format: uri + downloadTooLarge: + description: The content is too large for the server to serve. + content: + application/json: + schema: + $ref: definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_TOO_LARGE", + "error": "Content is too large to serve" + } + thumbnailRedirect: + description: A redirect to the thumbnail of the requested content. + headers: + Location: + description: The URL of the thumbnail content. + schema: + type: string + format: uri + headers: + downloadContentType: + description: | + The content type of the file that was previously uploaded. + + The server MUST return a `Content-Type` which is either exactly the same + as the original upload, or reasonably close. The bounds of "reasonable" + are: + + * Adding a charset to `text/*` content types. + * Detecting HTML and using `text/html` instead of `text/plain`. + * Using `application/octet-stream` when the server determines the + content type is obviously wrong. For example, an encrypted file being + claimed as `image/png`. + * Returning `application/octet-stream` when the media has an + unknown/unprovided `Content-Type`. For example, being uploaded before + the server tracked content types or when the remote server is + non-compliantly omitting the header entirely. + + Actions not in the spirit of the above are not considered "reasonable". + x-changedInMatrixVersion: + "1.12": | + This header became required in order to support `Content-Disposition`, + and the behaviour to compute its value was clarified. + required: true + schema: + type: string + diff --git a/data/api/client-server/create_room.yaml b/data/api/client-server/create_room.yaml index 2188a370..9e36d5e8 100644 --- a/data/api/client-server/create_room.yaml +++ b/data/api/client-server/create_room.yaml @@ -64,7 +64,8 @@ paths: `creation_content`. operationId: createRoom security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -209,7 +210,7 @@ paths: based on a preset. If unspecified, the server should use the `visibility` to determine - which preset to use. A visbility of `public` equates to a preset of + which preset to use. A visibility of `public` equates to a preset of `public_chat` and `private` visibility equates to a preset of `private_chat`. is_direct: @@ -290,4 +291,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/cross_signing.yaml b/data/api/client-server/cross_signing.yaml index 2f038e80..8f499d23 100644 --- a/data/api/client-server/cross_signing.yaml +++ b/data/api/client-server/cross_signing.yaml @@ -19,14 +19,30 @@ paths: /keys/device_signing/upload: post: x-addedInMatrixVersion: "1.1" + x-changedInMatrixVersion: + "1.11": UIA is not always required for this endpoint. summary: Upload cross-signing keys. description: |- Publishes cross-signing keys for the user. This API endpoint uses the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api). + + User-Interactive Authentication MUST be performed, except in these cases: + - there is no existing cross-signing master key uploaded to the homeserver, OR + - there is an existing cross-signing master key and it exactly matches the + cross-signing master key provided in the request body. If there are any additional + keys provided in the request (self-signing key, user-signing key) they MUST also + match the existing keys stored on the server. In other words, the request contains + no new keys. + + This allows clients to freely upload one set of keys, but not modify/overwrite keys if + they already exist. Allowing clients to upload the same set of keys more than once + makes this endpoint idempotent in the case where the response is lost over the network, + which would otherwise cause a UIA challenge upon retry. operationId: uploadCrossSigningKeys security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -150,23 +166,26 @@ paths: description: |- Publishes cross-signing signatures for the user. - The request body is a map from user ID to key ID to signed JSON object. The signed JSON object must match the key previously uploaded or retrieved for the given key ID, with the exception of the `signatures` property, which contains the new signature(s) to add. operationId: uploadCrossSigningSignatures security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: schema: type: object - title: Signatures - additionalProperties: - type: object - additionalProperties: + description: |- + A map of user ID to a map of key ID to signed JSON object. + patternProperties: + "^@": + x-pattern-format: mx-user-id type: object + additionalProperties: + type: object example: { "@alice:example.com": { "HIJKLMN": { @@ -236,11 +255,13 @@ paths: A map from user ID to key ID to an error for any signatures that failed. If a signature was invalid, the `errcode` will be set to `M_INVALID_SIGNATURE`. - additionalProperties: - type: object - additionalProperties: + patternProperties: + "^@": type: object - title: Error + x-pattern-format: mx-user-id + additionalProperties: + type: object + title: Error example: "@alice:example.com": HIJKLMN: @@ -262,4 +283,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/definitions/auth_data.yaml b/data/api/client-server/definitions/auth_data.yaml index 691cdc65..0186b24e 100644 --- a/data/api/client-server/definitions/auth_data.yaml +++ b/data/api/client-server/definitions/auth_data.yaml @@ -21,7 +21,7 @@ properties: The authentication type that the client is attempting to complete. May be omitted if `session` is given, and the client is reissuing a request which it believes has been completed out-of-band (for example, - via the [fallback mechanism](#fallback)). + via the [fallback mechanism](/client-server-api/#fallback)). type: string session: description: The value of the session key given by the homeserver. diff --git a/data/api/client-server/definitions/client_event_without_room_id.yaml b/data/api/client-server/definitions/client_event_without_room_id.yaml index d78dcc68..b12611a2 100644 --- a/data/api/client-server/definitions/client_event_without_room_id.yaml +++ b/data/api/client-server/definitions/client_event_without_room_id.yaml @@ -90,6 +90,7 @@ properties: "origin_server_ts": 1632491098485, "unsigned": { "age": 1257, + "membership": "leave" } } transaction_id: @@ -112,3 +113,23 @@ properties: this. title: EventContent type: object + membership: + description: | + The room membership of the user making the request, at the time of the event. + + This property is the value of the `membership` property of the + requesting user's [`m.room.member`](/client-server-api#mroommember) + state at the point of the event, including any changes caused by the + event. If the user had yet to join the room at the time of the event + (i.e, they have no `m.room.member` state), this property is set to + `leave`. + + Homeservers SHOULD populate this property + wherever practical, but they MAY omit it if necessary (for example, + if calculating the value is expensive, servers might choose to only + implement it in encrypted rooms). The property is *not* normally populated + in events pushed to application services via the application service transaction API + (where there is no clear definition of "requesting user"). + type: string + example: join + x-addedInMatrixVersion: "1.11" diff --git a/data/api/client-server/definitions/device_keys.yaml b/data/api/client-server/definitions/device_keys.yaml index ab033941..2a7f8104 100644 --- a/data/api/client-server/definitions/device_keys.yaml +++ b/data/api/client-server/definitions/device_keys.yaml @@ -53,10 +53,12 @@ properties: `:` to the signature. The signature is calculated using the process described at [Signing JSON](/appendices/#signing-json). - additionalProperties: - type: object - additionalProperties: - type: string + patternProperties: + "^@": + x-pattern-format: mx-user-id + type: object + additionalProperties: + type: string example: "@alice:example.com": "ed25519:JLAFKJWSCS": "dSO80A01XiigH3uBiDVx/EjzaoycHcjq9lfQX0uWsqxl2giMIiSPR8a4d291W1ihKJL/a+myXS367WT6NAIcBA" diff --git a/data/api/client-server/definitions/key_backup_session_data.yaml b/data/api/client-server/definitions/key_backup_session_data.yaml index 18963cbe..e2579142 100644 --- a/data/api/client-server/definitions/key_backup_session_data.yaml +++ b/data/api/client-server/definitions/key_backup_session_data.yaml @@ -14,7 +14,7 @@ type: object -title: SessionData +title: BackedUpSessionData description: |- The format of a backed-up session key, prior to encryption, when using the `m.megolm_backup.v1.curve25519-aes-sha2` algorithm. @@ -28,7 +28,8 @@ properties: items: type: string description: |- - Chain of Curve25519 keys through which this session was forwarded, via [m.forwarded_room_key](#mforwarded_room_key) events. + Chain of Curve25519 keys through which this session was forwarded, via [m.forwarded_room_key](/client-server-api/#mforwarded_room_key) + events. sender_key: type: string description: |- diff --git a/data/api/client-server/definitions/m.login.terms_params.yaml b/data/api/client-server/definitions/m.login.terms_params.yaml new file mode 100644 index 00000000..50c9da43 --- /dev/null +++ b/data/api/client-server/definitions/m.login.terms_params.yaml @@ -0,0 +1,83 @@ +# Copyright 2024 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +type: object +title: m.login.terms params +description: Schema for `m.login.terms` entry in the `params` object in a User-Interactive Authentication response. +required: ['policies'] +properties: + policies: + type: object + description: | + A map from "Policy ID" to the current definition of this policy document. The Policy ID is a unique + identifier for a given policy document, using the [Opaque Identifier Grammar](/appendices/#opaque-identifiers). + additionalProperties: + type: object + title: Policy Definition + required: [version] + properties: + version: + type: string + description: | + The version of this policy document. This is provided as a convenience for the client, + and uses the [Opaque Identifier Grammar](/appendices/#opaque-identifiers). + additionalProperties: + type: object + title: Policy Translation + required: [name, url] + description: | + Map from language codes to details of the document in that language. + Language codes SHOULD be formatted as per [Section 2.2 of RFC + 5646](https://datatracker.ietf.org/doc/html/rfc5646#section-2.2), + though some implementations may use an underscore instead of dash + (for example, `en_US` instead of `en-US`). + properties: + name: + type: string + description: | + The name of this document, in the appropriate language. An + arbitrary string with no specified maximum length. + url: + type: string + format: uri + description: | + A link to the text of this document, in the appropriate + language. MUST be a valid URI with scheme `https://` or + `http://`. Insecure HTTP is discouraged. +example: { + "policies": { + "terms_of_service": { + "version": "1.2", + "en": { + "name": "Terms of Service", + "url": "https://example.org/somewhere/terms-1.2-en.html" + }, + "fr": { + "name": "Conditions d'utilisation", + "url": "https://example.org/somewhere/terms-1.2-fr.html" + } + }, + "privacy_policy": { + "version": "1.2", + "en": { + "name": "Privacy Policy", + "url": "https://example.org/somewhere/privacy-1.2-en.html" + }, + "fr": { + "name": "Politique de confidentialité", + "url": "https://example.org/somewhere/privacy-1.2-fr.html" + } + } + } +} \ No newline at end of file diff --git a/data/api/client-server/definitions/m.mentions.yaml b/data/api/client-server/definitions/m.mentions.yaml index 806897b4..271ee5c5 100644 --- a/data/api/client-server/definitions/m.mentions.yaml +++ b/data/api/client-server/definitions/m.mentions.yaml @@ -18,17 +18,13 @@ description: |- Describes whether the event mentions other users or the room. This is contained within the event's `content` alongside other fields for the relevant event type. example: { - "body": "Hello Alice!", - "msgtype": "m.text", - "format": "org.matrix.custom.html", - "formatted_body": "Hello Alice!", - "m.mentions": { - "user_ids": ["@alice:example.org"] - } + "user_ids": ["@alice:example.org"] } properties: user_ids: - type: string[] + type: array + items: + type: string description: A list of Matrix IDs of mentioned users. room: type: boolean diff --git a/data/api/client-server/definitions/megolm_export_session_data.yaml b/data/api/client-server/definitions/megolm_export_session_data.yaml index 8c1e5010..ac4e4945 100644 --- a/data/api/client-server/definitions/megolm_export_session_data.yaml +++ b/data/api/client-server/definitions/megolm_export_session_data.yaml @@ -16,12 +16,13 @@ allOf: - $ref: key_backup_session_data.yaml - type: object + title: ExportedSessionData description: |- The format used to encode a Megolm session key for export. This is similar to the format before encryption used for the session keys - in [Server-side key backups](#server-side-key-backups) but adds the - `room_id` and `session_id` fields. + in [Server-side key backups](/client-server-api/#server-side-key-backups) + but adds the `room_id` and `session_id` fields. properties: room_id: type: string diff --git a/data/api/client-server/definitions/one_time_keys.yaml b/data/api/client-server/definitions/one_time_keys.yaml index ceb69291..78711350 100644 --- a/data/api/client-server/definitions/one_time_keys.yaml +++ b/data/api/client-server/definitions/one_time_keys.yaml @@ -9,6 +9,7 @@ additionalProperties: oneOf: - type: string - type: object + title: KeyObject properties: key: type: string @@ -18,7 +19,9 @@ additionalProperties: description: |- Signature for the device. Mapped from user ID to signature object, containing mapping from _key signing identifier_ to the signature - (see also: https://spec.matrix.org/v1.2/appendices/#signing-json) - additionalProperties: - type: object + (see also: [Signing JSON](/appendices/#signing-json)) + patternProperties: + "^@": + x-pattern-format: mx-user-id + type: object required: ['key', 'signatures'] diff --git a/data/api/client-server/definitions/push_condition.yaml b/data/api/client-server/definitions/push_condition.yaml index 8a3a9f32..1e7a8583 100644 --- a/data/api/client-server/definitions/push_condition.yaml +++ b/data/api/client-server/definitions/push_condition.yaml @@ -18,13 +18,13 @@ properties: kind: type: string description: |- - The kind of condition to apply. See [conditions](/client-server-api/#conditions) for + The kind of condition to apply. See [conditions](/client-server-api/#conditions-1) for more information on the allowed kinds and how they work. key: type: string description: |- - Required for `event_match` conditions. The dot-separated field of the - event to match. + Required for `event_match`, `event_property_is` and `event_property_contains` + conditions. The dot-separated field of the event to match. Required for `sender_notification_permission` conditions. The field in the power level event the user needs a minimum power level for. Fields @@ -43,5 +43,11 @@ properties: optionally prefixed by one of, ==, <, >, >= or <=. A prefix of < matches rooms where the member count is strictly less than the given number and so forth. If no prefix is present, this parameter defaults to ==. + value: + type: ["string", "integer", "boolean", "null"] + description: |- + Required for `event_property_is` and `event_property_contains` conditions. + A non-compound [canonical JSON](/appendices#canonical-json) value to match + against. required: - kind diff --git a/data/api/client-server/definitions/push_ruleset.yaml b/data/api/client-server/definitions/push_ruleset.yaml index 2d8cd67c..0a2148e0 100644 --- a/data/api/client-server/definitions/push_ruleset.yaml +++ b/data/api/client-server/definitions/push_ruleset.yaml @@ -14,37 +14,209 @@ properties: content: items: - allOf: - - $ref: push_rule.yaml - title: PushRule - type: object + $ref: push_rule.yaml type: array override: items: - allOf: - - $ref: push_rule.yaml - title: PushRule - type: object + $ref: push_rule.yaml type: array room: items: - allOf: - - $ref: push_rule.yaml - title: PushRule - type: object + $ref: push_rule.yaml type: array sender: items: - allOf: - - $ref: push_rule.yaml - title: PushRule - type: object + $ref: push_rule.yaml type: array underride: items: - allOf: - - $ref: push_rule.yaml - title: PushRule - type: object + $ref: push_rule.yaml type: array type: object +example: { + "content": [ + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight" + } + ], + "default": true, + "enabled": true, + "pattern": "alice", + "rule_id": ".m.rule.contains_user_name" + } + ], + "override": [ + { + "actions": [], + "conditions": [], + "default": true, + "enabled": false, + "rule_id": ".m.rule.master" + }, + { + "actions": [], + "conditions": [ + { + "key": "content.msgtype", + "kind": "event_match", + "pattern": "m.notice" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.suppress_notices" + } + ], + "room": [], + "sender": [], + "underride": [ + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "ring" + }, + { + "set_tweak": "highlight", + "value": false + } + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.call.invite" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.call" + }, + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight" + } + ], + "conditions": [ + { + "kind": "contains_display_name" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.contains_display_name" + }, + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight", + "value": false + } + ], + "conditions": [ + { + "kind": "room_member_count", + "is": "2" + }, + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.message" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.room_one_to_one" + }, + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight", + "value": false + } + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.member" + }, + { + "key": "content.membership", + "kind": "event_match", + "pattern": "invite" + }, + { + "key": "state_key", + "kind": "event_match", + "pattern": "@alice:example.com" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.invite_for_me" + }, + { + "actions": [ + "notify", + { + "set_tweak": "highlight", + "value": false + } + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.member" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.member_event" + }, + { + "actions": [ + "notify", + { + "set_tweak": "highlight", + "value": false + } + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.message" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.message" + } + ] +} diff --git a/data/api/client-server/definitions/room_key_backup.yaml b/data/api/client-server/definitions/room_key_backup.yaml index 5c70850f..ef7ef983 100644 --- a/data/api/client-server/definitions/room_key_backup.yaml +++ b/data/api/client-server/definitions/room_key_backup.yaml @@ -20,8 +20,7 @@ properties: type: object description: "A map of session IDs to key data." additionalProperties: - allOf: - - $ref: "key_backup_data.yaml" + $ref: "key_backup_data.yaml" example: { "sessionid1": { "first_message_index": 1, diff --git a/data/api/client-server/definitions/security.yaml b/data/api/client-server/definitions/security.yaml index 963e1d43..0c9bd1c7 100644 --- a/data/api/client-server/definitions/security.yaml +++ b/data/api/client-server/definitions/security.yaml @@ -11,8 +11,37 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -accessToken: +accessTokenQuery: type: apiKey - description: The access_token returned by a call to `/login` or `/register` + description: |- + **Deprecated.** The `access_token` returned by a call to `/login` or `/register`, as a query + parameter. + + It can also be the `as_token` of an application service. name: access_token in: query +accessTokenBearer: + type: http + description: |- + The `access_token` returned by a call to `/login` or `/register`, using the + `Authorization: Bearer` header. + + It can also be the `as_token` of an application service. + + This is the preferred method. + scheme: bearer +appserviceAccessTokenQuery: + type: apiKey + description: |- + **Deprecated.** The `as_token` of an application service, as a query + parameter. + name: access_token + in: query +appserviceAccessTokenBearer: + type: http + description: |- + The `as_token` of an application service, using the `Authorization: Bearer` + header. + + This is the preferred method. + scheme: bearer diff --git a/data/api/client-server/definitions/sso_login_flow.yaml b/data/api/client-server/definitions/sso_login_flow.yaml index ca2a6602..0996511e 100644 --- a/data/api/client-server/definitions/sso_login_flow.yaml +++ b/data/api/client-server/definitions/sso_login_flow.yaml @@ -15,7 +15,7 @@ type: object title: m.login.sso flow schema properties: type: - type: enum + type: string enum: ["m.login.sso"] description: The string `m.login.sso` example: "m.login.sso" @@ -40,10 +40,7 @@ properties: description: |- Opaque string chosen by the homeserver, uniquely identifying the IdP from other IdPs the homeserver might support. Should - be between 1 and 255 characters in length, containing unreserved - characters under [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt) - (`ALPHA DIGIT "-" / "." / "_" / "~"`). Clients are not intended - to parse or infer meaning from opaque strings. + use the [Opaque identifier Grammar](/appendices#opaque-identifiers). example: "com.example.idp.github" name: type: string @@ -56,6 +53,18 @@ properties: description: |- Optional `mxc://` URI to provide an image/icon representing the IdP. Intended to be shown alongside the `name` if provided. + + {{% boxes/note %}} + Clients SHOULD use the deprecated [`/download`](/client-server-api/#get_matrixmediav3downloadservernamemediaid) + and [`/thumbnail`](/client-server-api/#get_matrixmediav3thumbnailservernamemediaid) + endpoints to retrieve this media item because clients will not have + an access token they can authenticate with yet. Servers SHOULD ensure + media used for IdP icons is excluded from the freeze described by the + [Content Repository module's Client Behaviour section](/client-server-api/#content-repo-client-behaviour). + + This may be addressed in the future with proposals like [MSC4148](https://github.com/matrix-org/matrix-spec-proposals/pull/4148), + or removed entirely through the transition to OIDC. + {{% /boxes/note %}} example: "mxc://example.org/abc123" brand: type: string diff --git a/data/api/client-server/definitions/sync_filter.yaml b/data/api/client-server/definitions/sync_filter.yaml index 1b98db1f..75544e94 100644 --- a/data/api/client-server/definitions/sync_filter.yaml +++ b/data/api/client-server/definitions/sync_filter.yaml @@ -69,7 +69,6 @@ properties: type: boolean state: type: object - title: StateFilter allOf: - $ref: room_event_filter.yaml description: The state events to include for rooms. diff --git a/data/api/client-server/definitions/tag.yaml b/data/api/client-server/definitions/tag.yaml new file mode 100644 index 00000000..05c911a5 --- /dev/null +++ b/data/api/client-server/definitions/tag.yaml @@ -0,0 +1,24 @@ +# Copyright 2020-2024 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +title: Tag +type: object +properties: + order: + type: number + format: float + description: |- + A number in a range `[0,1]` describing a relative + position of the room under the given tag. + example: 0.25 diff --git a/data/api/client-server/definitions/timeline_batch.yaml b/data/api/client-server/definitions/timeline_batch.yaml index 1c4ba40e..5b95f583 100644 --- a/data/api/client-server/definitions/timeline_batch.yaml +++ b/data/api/client-server/definitions/timeline_batch.yaml @@ -19,7 +19,7 @@ properties: type: boolean prev_batch: description: A token that can be supplied to the `from` parameter of the - [`/rooms//messages`](#get_matrixclientv3roomsroomidmessages) + [`/rooms//messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages) endpoint in order to retrieve earlier events. If no earlier events are available, this property may be omitted from diff --git a/data/api/client-server/definitions/user_identifier.yaml b/data/api/client-server/definitions/user_identifier.yaml index 7e6eca9c..add848fd 100644 --- a/data/api/client-server/definitions/user_identifier.yaml +++ b/data/api/client-server/definitions/user_identifier.yaml @@ -18,7 +18,10 @@ type: object properties: type: type: string - description: The type of identification. See [Identifier types](/client-server-api/#identifier-types) for supported values and additional property descriptions. + description: |- + The type of identification. See [Identifier types](/client-server-api/#identifier-types) + for supported values and additional property descriptions. required: - type -additionalProperties: true +additionalProperties: + description: Keys dependent on the identification type. diff --git a/data/api/client-server/definitions/wellknown/full.yaml b/data/api/client-server/definitions/wellknown/full.yaml index 8d8f4038..eaa9294a 100644 --- a/data/api/client-server/definitions/wellknown/full.yaml +++ b/data/api/client-server/definitions/wellknown/full.yaml @@ -22,7 +22,6 @@ properties: "m.identity_server": $ref: "identity_server.yaml" additionalProperties: - type: object description: Application-dependent keys using Java package naming convention. required: - m.homeserver diff --git a/data/api/client-server/device_management.yaml b/data/api/client-server/device_management.yaml index 32d3db9a..b2bcb8ce 100644 --- a/data/api/client-server/device_management.yaml +++ b/data/api/client-server/device_management.yaml @@ -22,7 +22,8 @@ paths: description: Gets information about all devices for the current user. operationId: getDevices security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: Device information @@ -35,9 +36,7 @@ paths: type: array description: A list of all registered devices for this user. items: - type: object - allOf: - - $ref: definitions/client_device.yaml + $ref: definitions/client_device.yaml examples: response: value: { @@ -58,7 +57,8 @@ paths: description: Gets information on a single device, by device id. operationId: getDevice security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: deviceId @@ -73,9 +73,7 @@ paths: content: application/json: schema: - type: object - allOf: - - $ref: definitions/client_device.yaml + $ref: definitions/client_device.yaml examples: response: value: { @@ -93,7 +91,8 @@ paths: description: Updates the metadata on the given device. operationId: updateDevice security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: deviceId @@ -140,7 +139,8 @@ paths: Deletes the given device, and invalidates any access token associated with it. operationId: deleteDevice security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: deviceId @@ -191,7 +191,8 @@ paths: Deletes the given devices, and invalidates any access token associated with them. operationId: deleteDevices security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -250,4 +251,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/directory.yaml b/data/api/client-server/directory.yaml index df29fbf8..f5c357d9 100644 --- a/data/api/client-server/directory.yaml +++ b/data/api/client-server/directory.yaml @@ -21,7 +21,8 @@ paths: summary: Create a new mapping from room alias to room ID. operationId: setRoomAlias security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomAlias @@ -172,7 +173,8 @@ paths: have permission to update the `m.room.canonical_alias` event. operationId: deleteRoomAlias security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomAlias @@ -229,7 +231,8 @@ paths: state event. operationId: getLocalAliases security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -309,4 +312,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/event_context.yaml b/data/api/client-server/event_context.yaml index 0d740241..0c927a6d 100644 --- a/data/api/client-server/event_context.yaml +++ b/data/api/client-server/event_context.yaml @@ -28,7 +28,8 @@ paths: [Lazy-loading room members](/client-server-api/#lazy-loading-room-members) for more information. operationId: getEventContext security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -154,4 +155,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/filter.yaml b/data/api/client-server/filter.yaml index 8405f81e..f1135939 100644 --- a/data/api/client-server/filter.yaml +++ b/data/api/client-server/filter.yaml @@ -25,7 +25,8 @@ paths: restrict which events are returned to the client. operationId: defineFilter security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -119,7 +120,8 @@ paths: summary: Download a filter operationId: getFilter security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -141,9 +143,7 @@ paths: content: application/json: schema: - type: object - allOf: - - $ref: definitions/sync_filter.yaml + $ref: definitions/sync_filter.yaml examples: response: value: { @@ -214,4 +214,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/inviting.yaml b/data/api/client-server/inviting.yaml index ce5d503d..6aa9e08a 100644 --- a/data/api/client-server/inviting.yaml +++ b/data/api/client-server/inviting.yaml @@ -38,7 +38,8 @@ paths: `m.room.member` event to the room. operationId: inviteUser security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -136,4 +137,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/joining.yaml b/data/api/client-server/joining.yaml index 020c5a0e..1019abbd 100644 --- a/data/api/client-server/joining.yaml +++ b/data/api/client-server/joining.yaml @@ -18,12 +18,12 @@ info: paths: "/rooms/{roomId}/join": post: - summary: Start the requesting user participating in a particular room. + summary: Join the requesting user to a particular room. description: |- *Note that this API requires a room ID, not alias.* `/join/{roomIdOrAlias}` *exists if you have a room alias.* - This API starts a user participating in a particular room, if that user + This API starts a user's participation in a particular room, if that user is allowed to participate in that room. After this call, the client is allowed to see all current state events in the room, and all subsequent events associated with the room until the user leaves the room. @@ -33,7 +33,8 @@ paths: and [`/sync`](/client-server-api/#get_matrixclientv3sync) APIs. operationId: joinRoomById security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -112,11 +113,11 @@ paths: - Room membership "/join/{roomIdOrAlias}": post: - summary: Start the requesting user participating in a particular room. + summary: Join the requesting user to a particular room. description: |- *Note that this API takes either a room ID or alias, unlike* `/rooms/{roomId}/join`. - This API starts a user participating in a particular room, if that user + This API starts a user's participation in a particular room, if that user is allowed to participate in that room. After this call, the client is allowed to see all current state events in the room, and all subsequent events associated with the room until the user leaves the room. @@ -126,7 +127,8 @@ paths: and [`/sync`](/client-server-api/#get_matrixclientv3sync) APIs. operationId: joinRoom security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomIdOrAlias @@ -137,6 +139,32 @@ paths: type: string - in: query name: server_name + deprecated: true + x-changedInMatrixVersion: + "1.12": |- + This parameter has been deprecated in favour of `via` and will be removed in + a future version of the spec. + + Clients SHOULD use `via` when the homeserver they're talking to supports it. + To do this, they MAY either detect server support through the supported spec + versions in [`/_matrix/client/versions`](/client-server-api/#get_matrixclientversions) + or always include both parameters with identical values. + + Homeservers MUST ignore all `server_name` parameters if any `via` parameters + are supplied. + description: |- + The servers to attempt to join the room through. One of the servers + must be participating in the room. + example: + - matrix.org + - elsewhere.ca + schema: + type: array + items: + type: string + - in: query + name: via + x-addedInMatrixVersion: "1.12" description: |- The servers to attempt to join the room through. One of the servers must be participating in the room. @@ -229,4 +257,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/key_backup.yaml b/data/api/client-server/key_backup.yaml index cd7cf5a0..64833f6e 100644 --- a/data/api/client-server/key_backup.yaml +++ b/data/api/client-server/key_backup.yaml @@ -23,7 +23,8 @@ paths: description: Creates a new backup. operationId: postRoomKeysVersion security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -80,7 +81,8 @@ paths: description: Get information about the latest backup version. operationId: getRoomKeysVersionCurrent security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: The information about the backup. @@ -155,7 +157,8 @@ paths: description: Get information about an existing backup. operationId: getRoomKeysVersion security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: version @@ -242,7 +245,8 @@ paths: be modified. operationId: putRoomKeysVersion security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: version @@ -344,7 +348,8 @@ paths: as well as all key data related to the backup will be deleted. operationId: deleteRoomKeysVersion security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: version @@ -396,7 +401,8 @@ paths: description: Store a key in the backup. operationId: putRoomKeyBySessionId security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: version @@ -478,7 +484,8 @@ paths: description: Retrieve a key from the backup. operationId: getRoomKeyBySessionId security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: version @@ -534,7 +541,8 @@ paths: description: Delete a key from the backup. operationId: deleteRoomKeyBySessionId security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: version @@ -606,7 +614,8 @@ paths: description: Store several keys in the backup for a given room. operationId: putRoomKeysByRoomId security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: version @@ -693,7 +702,8 @@ paths: description: Retrieve the keys from the backup for a given room. operationId: getRoomKeysByRoomId security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: version @@ -745,7 +755,8 @@ paths: description: Delete the keys from the backup for a given room. operationId: deleteRoomKeysByRoomId security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: version @@ -810,7 +821,8 @@ paths: description: Store several keys in the backup. operationId: putRoomKeys security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: version @@ -828,9 +840,11 @@ paths: rooms: type: object description: A map of room IDs to room key backup data. - additionalProperties: - allOf: - - $ref: definitions/room_key_backup.yaml + patternProperties: + "^!": + x-pattern-format: mx-room-id + allOf: + - $ref: definitions/room_key_backup.yaml example: "!room:example.org": sessions: @@ -910,7 +924,8 @@ paths: description: Retrieve the keys from the backup. operationId: getRoomKeys security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: version @@ -932,9 +947,11 @@ paths: rooms: type: object description: A map of room IDs to room key backup data. - additionalProperties: - allOf: - - $ref: definitions/room_key_backup.yaml + patternProperties: + "^!": + x-pattern-format: mx-room-id + allOf: + - $ref: definitions/room_key_backup.yaml example: "!room:example.org": sessions: @@ -974,7 +991,8 @@ paths: description: Delete the keys from the backup. operationId: deleteRoomKeys security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: version @@ -1039,4 +1057,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/keys.yaml b/data/api/client-server/keys.yaml index cb8a11db..de4501b3 100644 --- a/data/api/client-server/keys.yaml +++ b/data/api/client-server/keys.yaml @@ -24,7 +24,8 @@ paths: description: Publishes end-to-end encryption keys for the device. operationId: uploadKeys security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -38,12 +39,9 @@ paths: allOf: - $ref: definitions/device_keys.yaml one_time_keys: - # $ref: "definitions/one_time_keys.yaml" - # XXX: We can't define an actual object here, so we have to hope - # that people will look at the swagger source or can figure it out - # from the other endpoints/example. + allOf: + - $ref: "definitions/one_time_keys.yaml" type: object - title: OneTimeKeys description: |- One-time public keys for "pre-key" messages. The names of the properties should be in the format @@ -52,7 +50,6 @@ paths: May be absent if no new one-time keys are required. example: - curve25519:AAAAAQ: /qyvZvwjiTxGdGU0RCguDCLeR+nmsb3FfNG3/Ve4vU8 signed_curve25519:AAAAHg: key: zKbLg+NrIjpnagy+pIY6uPL4ZwEG2v+8F9lmgsnlZzs signatures: @@ -65,10 +62,9 @@ paths: ed25519:JLAFKJWSCS: IQeCEPb9HFk217cU9kw9EOiusC6kMIkoIRnbnfOh5Oc63S1ghgyjShBGpu34blQomoalCyXWyhaaT3MrLZYQAA fallback_keys: x-addedInMatrixVersion: "1.2" - # $ref: "definitions/one_time_keys.yaml" - # XXX: We can't define an actual object here - see above. + allOf: + - $ref: "definitions/one_time_keys.yaml" type: object - title: OneTimeKeys description: |- The public key which should be used if the device's one-time keys are exhausted. The fallback key is not deleted once used, but should @@ -84,7 +80,6 @@ paths: May be absent if a new fallback key is not required. example: - curve25519:AAAAAG: /qyvZvwjiTxGdGU0RCguDCLeR+nmsb3FfNG3/Ve4vU8 signed_curve25519:AAAAGj: key: zKbLg+NrIjpnagy+pIY6uPL4ZwEG2v+8F9lmgsnlZzs fallback: true @@ -111,7 +106,6 @@ paths: If an algorithm is not listed, the count for that algorithm is to be assumed zero. example: - curve25519: 10 signed_curve25519: 20 required: - one_time_key_counts @@ -123,7 +117,8 @@ paths: description: Returns the current devices and identity keys for the given users. operationId: queryKeys security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -142,11 +137,13 @@ paths: The keys to be downloaded. A map from user ID, to a list of device IDs, or to an empty list to indicate all devices for the corresponding user. - additionalProperties: - type: array - items: - type: string - description: device ID + patternProperties: + "^@": + x-pattern-format: mx-user-id + type: array + items: + type: string + description: device ID example: "@alice:example.com": [] required: @@ -182,24 +179,26 @@ paths: the information returned will be the same as uploaded via `/keys/upload`, with the addition of an `unsigned` property. - additionalProperties: - type: object - additionalProperties: - title: DeviceInformation - allOf: - - $ref: definitions/device_keys.yaml - properties: - unsigned: - title: UnsignedDeviceInfo - type: object - description: |- - Additional data added to the device key information - by intermediate servers, and not covered by the - signatures. - properties: - device_display_name: - type: string - description: The display name which the user set on the device. + patternProperties: + "^@": + x-pattern-format: mx-user-id + type: object + additionalProperties: + title: DeviceInformation + allOf: + - $ref: definitions/device_keys.yaml + properties: + unsigned: + title: UnsignedDeviceInfo + type: object + description: |- + Additional data added to the device key information + by intermediate servers, and not covered by the + signatures. + properties: + device_display_name: + type: string + description: The display name which the user set on the device. example: "@alice:example.com": JLAFKJWSCS: @@ -226,9 +225,11 @@ paths: `/keys/device_signing/upload`, along with the signatures uploaded via `/keys/signatures/upload` that the requesting user is allowed to see. - additionalProperties: - allOf: - - $ref: definitions/cross_signing_key.yaml + patternProperties: + "^@": + x-pattern-format: mx-user-id + allOf: + - $ref: definitions/cross_signing_key.yaml example: "@alice:example.com": user_id: "@alice:example.com" @@ -244,9 +245,11 @@ paths: from user ID, to self-signing key information. For each key, the information returned will be the same as uploaded via `/keys/device_signing/upload`. - additionalProperties: - allOf: - - $ref: definitions/cross_signing_key.yaml + patternProperties: + "^@": + x-pattern-format: mx-user-id + allOf: + - $ref: definitions/cross_signing_key.yaml example: "@alice:example.com": user_id: "@alice:example.com" @@ -265,9 +268,11 @@ paths: from user ID, to user-signing key information. The information returned will be the same as uploaded via `/keys/device_signing/upload`. - additionalProperties: - allOf: - - $ref: definitions/cross_signing_key.yaml + patternProperties: + "^@": + x-pattern-format: mx-user-id + allOf: + - $ref: definitions/cross_signing_key.yaml example: "@alice:example.com": user_id: "@alice:example.com" @@ -283,10 +288,26 @@ paths: /keys/claim: post: summary: Claim one-time encryption keys. - description: Claims one-time keys for use in pre-key messages. + description: |- + Claims one-time keys for use in pre-key messages. + + The request contains the user ID, device ID and algorithm name of the + keys that are required. If a key matching these requirements can be + found, the response contains it. The returned key is a one-time key + if one is available, and otherwise a fallback key. + + One-time keys are given out in the order that they were uploaded via + [/keys/upload](/client-server-api/#post_matrixclientv3keysupload). (All + keys uploaded within a given call to `/keys/upload` are considered + equivalent in this regard; no ordering is specified within them.) + + Servers must ensure that each one-time key is returned at most once, + so when a key has been returned, no other request will ever return + the same key. operationId: claimKeys security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -304,12 +325,14 @@ paths: description: |- The keys to be claimed. A map from user ID, to a map from device ID to algorithm name. - additionalProperties: - type: object - additionalProperties: - type: string - description: algorithm - example: signed_curve25519 + patternProperties: + "^@": + x-pattern-format: mx-user-id + type: object + additionalProperties: + type: string + description: algorithm + example: signed_curve25519 example: "@alice:example.com": JLAFKJWSCS: signed_curve25519 @@ -349,16 +372,12 @@ paths: If necessary, the claimed key might be a fallback key. Fallback keys are re-used by the server until replaced by the device. - additionalProperties: - type: object - additionalProperties: - # $ref: "definitions/one_time_keys.yaml" - # XXX: We can't define an actual object here, so we have to hope - # that people will read the link provided in the description - # and figure it out from the other endpoints/example. - # See also one_time_key parameter for /keys/upload above. + patternProperties: + "^@": + x-pattern-format: mx-user-id type: object - title: OneTimeKeys + additionalProperties: + $ref: "definitions/one_time_keys.yaml" example: "@alice:example.com": JLAFKJWSCS: @@ -386,7 +405,8 @@ paths: identity keys, between `from` and `to`. operationId: getKeysChanges security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: from @@ -456,4 +476,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/kicking.yaml b/data/api/client-server/kicking.yaml index 6eaa8243..eb5b02d2 100644 --- a/data/api/client-server/kicking.yaml +++ b/data/api/client-server/kicking.yaml @@ -29,7 +29,8 @@ paths: the target member's state by making a request to `/rooms//state/m.room.member/`. operationId: kick security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -103,4 +104,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/knocking.yaml b/data/api/client-server/knocking.yaml index b778f02b..085aa74f 100644 --- a/data/api/client-server/knocking.yaml +++ b/data/api/client-server/knocking.yaml @@ -38,7 +38,8 @@ paths: [`/sync`](/client-server-api/#get_matrixclientv3sync) API. operationId: knockRoom security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomIdOrAlias @@ -49,6 +50,32 @@ paths: type: string - in: query name: server_name + deprecated: true + x-changedInMatrixVersion: + "1.12": |- + This parameter has been deprecated in favour of `via` and will be removed in + a future version of the spec. + + Clients SHOULD use `via` when the homeserver they're talking to supports it. + To do this, they MAY either detect server support through the supported spec + versions in [`/_matrix/client/versions`](/client-server-api/#get_matrixclientversions) + or always include both parameters with identical values. + + Homeservers MUST ignore all `server_name` parameters if any `via` parameters + are supplied. + description: |- + The servers to attempt to knock on the room through. One of the servers + must be participating in the room. + example: + - matrix.org + - elsewhere.ca + schema: + type: array + items: + type: string + - in: query + name: via + x-addedInMatrixVersion: "1.12" description: |- The servers to attempt to knock on the room through. One of the servers must be participating in the room. @@ -144,4 +171,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/leaving.yaml b/data/api/client-server/leaving.yaml index 6e7d67d0..6bdadb08 100644 --- a/data/api/client-server/leaving.yaml +++ b/data/api/client-server/leaving.yaml @@ -33,7 +33,8 @@ paths: they were previously allowed to see. operationId: leaveRoom security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -91,7 +92,8 @@ paths: before calling this API. operationId: forgetRoom security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -144,4 +146,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/list_joined_rooms.yaml b/data/api/client-server/list_joined_rooms.yaml index 68451409..cec458c8 100644 --- a/data/api/client-server/list_joined_rooms.yaml +++ b/data/api/client-server/list_joined_rooms.yaml @@ -22,7 +22,8 @@ paths: description: This API returns a list of the user's current rooms. operationId: getJoinedRooms security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: A list of the rooms the user is in. @@ -61,4 +62,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/list_public_rooms.yaml b/data/api/client-server/list_public_rooms.yaml index ba816b06..497ccb44 100644 --- a/data/api/client-server/list_public_rooms.yaml +++ b/data/api/client-server/list_public_rooms.yaml @@ -74,7 +74,8 @@ paths: the room creator or a server administrator. operationId: setRoomVisibilityOnDirectory security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -154,7 +155,7 @@ paths: name: server description: |- The server to fetch the public room lists from. Defaults to the - local server. + local server. Case sensitive. schema: type: string responses: @@ -175,13 +176,14 @@ paths: of joined members, with the largest rooms first. operationId: queryPublicRooms security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: server description: |- The server to fetch the public room lists from. Defaults to the - local server. + local server. Case sensitive. schema: type: string requestBody: @@ -267,3 +269,9 @@ servers: default: localhost:8008 basePath: default: /_matrix/client/v3 +components: + securitySchemes: + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer \ No newline at end of file diff --git a/data/api/client-server/login.yaml b/data/api/client-server/login.yaml index a8953e65..28de0be1 100644 --- a/data/api/client-server/login.yaml +++ b/data/api/client-server/login.yaml @@ -109,23 +109,28 @@ paths: properties: type: type: string - enum: - - m.login.password - - m.login.token - description: The login type being used. + description: |- + The login type being used. + + This must be a type returned in one of the flows of the + response of the [`GET /login`](/client-server-api/#get_matrixclientv3login) + endpoint, like `m.login.password` or `m.login.token`. identifier: $ref: definitions/user_identifier.yaml user: type: string + deprecated: true description: The fully qualified user ID or just local part of the user ID, to log in. Deprecated in favour of `identifier`. medium: type: string + deprecated: true description: When logging in using a third-party identifier, the medium of the identifier. Must be 'email'. Deprecated in favour of `identifier`. address: type: string + deprecated: true description: Third-party identifier for the user. Deprecated in favour of `identifier`. password: @@ -167,6 +172,8 @@ paths: properties: user_id: type: string + format: mx-user-id + pattern: "^@" description: The fully-qualified Matrix ID for the account. access_token: type: string @@ -192,6 +199,8 @@ paths: x-addedInMatrixVersion: "1.3" home_server: type: string + format: mx-server-name + deprecated: true description: |- The server_name of the homeserver on which the account has been registered. @@ -284,4 +293,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/login_token.yaml b/data/api/client-server/login_token.yaml index 73e607d1..f14e1a0a 100644 --- a/data/api/client-server/login_token.yaml +++ b/data/api/client-server/login_token.yaml @@ -33,19 +33,19 @@ paths: Clients, both authenticated and unauthenticated, might wish to hide user interface which exposes this feature if the server is not offering it. Authenticated clients can check for support on - a per-user basis with the `m.get_login_token` [capability](/client-server-api/#capabilities-negotiation), + a per-user basis with the [`m.get_login_token`](/client-server-api/#mget_login_token-capability) capability, while unauthenticated clients can detect server support by looking for an `m.login.token` login flow with `get_login_token: true` on [`GET /login`](/client-server-api/#post_matrixclientv3login). In v1.7 of the specification, transmission of the generated token to an unauthenticated client is left as an implementation detail. Future MSCs such as [MSC3906](https://github.com/matrix-org/matrix-spec-proposals/pull/3906) - might standarise a way to transmit the token between clients. + might standardise a way to transmit the token between clients. The generated token MUST only be valid for a single login, enforced by the server. Clients which intend to log in multiple devices must generate a token for each. With other User-Interactive Authentication (UIA)-supporting endpoints, servers sometimes do not re-prompt - for verification if the session recently passed UIA. For this endpoint, servers should always re-prompt + for verification if the session recently passed UIA. For this endpoint, servers MUST always re-prompt the user for verification to ensure explicit consent is gained for each additional client. Servers are encouraged to apply stricter than normal rate limiting to this endpoint, such as maximum @@ -53,7 +53,8 @@ paths: operationId: generateLoginToken x-addedInMatrixVersion: "1.7" security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -97,8 +98,8 @@ paths: The request was malformed, or the user does not have an ability to generate tokens for their devices, as implied by the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api). - Clients should verify whether the user has an ability to call this endpoint with the `m.get_login_token` - [capability](/client-server-api/#capabilities-negotiation). + Clients should verify whether the user has an ability to call this endpoint with the + [`m.get_login_token`](/client-server-api/#mget_login_token-capability) capability. content: application/json: schema: @@ -131,4 +132,7 @@ servers: default: /_matrix/client/v1 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/logout.yaml b/data/api/client-server/logout.yaml index c3287472..60464932 100644 --- a/data/api/client-server/logout.yaml +++ b/data/api/client-server/logout.yaml @@ -25,7 +25,8 @@ paths: [Device keys](/client-server-api/#device-keys) for the device are deleted alongside the device. operationId: logout security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: The access token used in the request was successfully invalidated. @@ -53,7 +54,8 @@ paths: this way. operationId: logout_all security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: The user's access tokens were successfully invalidated. @@ -78,4 +80,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/message_pagination.yaml b/data/api/client-server/message_pagination.yaml index 07c16497..4d5c94e1 100644 --- a/data/api/client-server/message_pagination.yaml +++ b/data/api/client-server/message_pagination.yaml @@ -27,7 +27,8 @@ paths: [Lazy-loading room members](/client-server-api/#lazy-loading-room-members) for more information. operationId: getRoomEvents security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -185,4 +186,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/notifications.yaml b/data/api/client-server/notifications.yaml index 21d6640a..03db22af 100644 --- a/data/api/client-server/notifications.yaml +++ b/data/api/client-server/notifications.yaml @@ -24,7 +24,8 @@ paths: user has been, or would have been notified about. operationId: getNotifications security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: from @@ -145,4 +146,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/old_sync.yaml b/data/api/client-server/old_sync.yaml index 540c97c7..0a3c0439 100644 --- a/data/api/client-server/old_sync.yaml +++ b/data/api/client-server/old_sync.yaml @@ -29,7 +29,8 @@ paths: the [migration guide](https://matrix.org/docs/guides/migrating-from-client-server-api-v-1#deprecated-endpoints). operationId: getEvents security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: from @@ -99,7 +100,8 @@ paths: the [migration guide](https://matrix.org/docs/guides/migrating-from-client-server-api-v-1#deprecated-endpoints). operationId: initialSync security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: limit @@ -137,7 +139,7 @@ paths: type: array description: A list of presence events. items: - $ref: definitions/client_event.yaml + $ref: ../../event-schemas/schema/core-event-schema/event.yaml rooms: type: array items: @@ -171,7 +173,7 @@ paths: description: |- A token which correlates to the start of `chunk`. Can be passed to - [`/rooms//messages`](#get_matrixclientv3roomsroomidmessages) + [`/rooms//messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages) to retrieve earlier events. If no earlier events are available, this property may be omitted from @@ -181,7 +183,7 @@ paths: description: |- A token which correlates to the end of `chunk`. Can be passed to - [`/rooms//messages`](#get_matrixclientv3roomsroomidmessages) + [`/rooms//messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages) to retrieve later events. chunk: type: array @@ -219,7 +221,7 @@ paths: The private data that this user has attached to this room. items: - $ref: definitions/client_event.yaml + $ref: ../../event-schemas/schema/core-event-schema/event.yaml required: - room_id - membership @@ -227,10 +229,7 @@ paths: type: array description: The global private data created by this user. items: - title: Event - type: object - allOf: - - $ref: ../../event-schemas/schema/core-event-schema/event.yaml + $ref: ../../event-schemas/schema/core-event-schema/event.yaml required: - end - rooms @@ -328,7 +327,8 @@ paths: or the [/rooms/{roomId}/context/{eventId](/client-server-api/#get_matrixclientv3roomsroomidcontexteventid) API. operationId: getOneEvent security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: eventId @@ -369,4 +369,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/openid.yaml b/data/api/client-server/openid.yaml index 2dbd1227..a65f9fef 100644 --- a/data/api/client-server/openid.yaml +++ b/data/api/client-server/openid.yaml @@ -30,7 +30,8 @@ paths: example. operationId: requestOpenIdToken security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -91,4 +92,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/peeking_events.yaml b/data/api/client-server/peeking_events.yaml index b323d940..eaea5bbb 100644 --- a/data/api/client-server/peeking_events.yaml +++ b/data/api/client-server/peeking_events.yaml @@ -34,7 +34,8 @@ paths: yet known. operationId: peekEvents security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: from @@ -114,4 +115,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/presence.yaml b/data/api/client-server/presence.yaml index caa19854..d3141911 100644 --- a/data/api/client-server/presence.yaml +++ b/data/api/client-server/presence.yaml @@ -26,7 +26,8 @@ paths: presence state of another user. operationId: setPresence security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -82,7 +83,8 @@ paths: description: Get the given user's presence state. operationId: getPresence security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -161,4 +163,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/profile.yaml b/data/api/client-server/profile.yaml index b47cf591..6e588ae3 100644 --- a/data/api/client-server/profile.yaml +++ b/data/api/client-server/profile.yaml @@ -24,7 +24,8 @@ paths: set this user's display name, e.g. you need to have their `access_token`. operationId: setDisplayName security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -97,6 +98,20 @@ paths: value: { "displayname": "Alice Margatroid" } + "403": + x-addedInMatrixVersion: "1.12" + description: The server is unwilling to disclose whether the user exists and/or + has a display name. + content: + application/json: + schema: + $ref: definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_FORBIDDEN", + "error": "Profile lookup is disabled on this homeserver" + } "404": description: There is no display name for this user or this user does not exist. tags: @@ -109,7 +124,8 @@ paths: set this user's avatar URL, e.g. you need to have their `access_token`. operationId: setAvatarUrl security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -183,6 +199,20 @@ paths: value: { "avatar_url": "mxc://matrix.org/SDGdghriugerRg" } + "403": + x-addedInMatrixVersion: "1.12" + description: The server is unwilling to disclose whether the user exists and/or + has an avatar URL. + content: + application/json: + schema: + $ref: definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_FORBIDDEN", + "error": "Profile lookup is disabled on this homeserver" + } "404": description: There is no avatar URL for this user or this user does not exist. tags: @@ -193,8 +223,7 @@ paths: description: |- Get the combined profile information for this user. This API may be used to fetch the user's own profile information or other users; either - locally or on remote homeservers. This API may return keys which are not - limited to `displayname` or `avatar_url`. + locally or on remote homeservers. operationId: getUserProfile parameters: - in: path @@ -238,7 +267,7 @@ paths: response: value: { "errcode": "M_FORBIDDEN", - "error": "Profile lookup over federation is disabled on this homeserver" + "error": "Profile lookup is disabled on this homeserver" } "404": description: There is no profile information for this user or this user does not @@ -269,4 +298,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/pusher.yaml b/data/api/client-server/pusher.yaml index c686e9ae..d2a59204 100644 --- a/data/api/client-server/pusher.yaml +++ b/data/api/client-server/pusher.yaml @@ -23,7 +23,8 @@ paths: description: Gets all currently active pushers for the authenticated user. operationId: getPushers security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: The pushers for this user. @@ -136,7 +137,8 @@ paths: user is deleted. operationId: postPusher security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -208,17 +210,21 @@ paths: type: object description: |- Required if `kind` is not `null`. A dictionary of information - for the pusher implementation itself. If `kind` is `http`, - this should contain `url` which is the URL to use to send - notifications to. + for the pusher implementation itself. + + If `kind` is `http`, this MUST contain `url` which is the URL + to use for sending notifications. Clients MAY use this object + to pass custom data to their push gateway. Servers MUST forward + the entire content including `format` and any custom keys but excluding `url` + when calling [`/_matrix/push/v1/notify`](/push-gateway-api/#post_matrixpushv1notify). title: PusherData properties: url: type: string format: uri description: |- - Required if `kind` is `http`. The URL to use to send - notifications to. MUST be an HTTPS URL with a path of + Required if `kind` is `http`. The URL to use for sending + notifications. MUST be an HTTPS URL with a path of `/_matrix/push/v1/notify`. example: https://push-gateway.location.here/_matrix/push/v1/notify format: @@ -288,4 +294,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/pushrules.yaml b/data/api/client-server/pushrules.yaml index 57638583..fd56f46e 100644 --- a/data/api/client-server/pushrules.yaml +++ b/data/api/client-server/pushrules.yaml @@ -20,13 +20,12 @@ paths: get: summary: Retrieve all push rulesets. description: |- - Retrieve all push rulesets for this user. Clients can "drill-down" on - the rulesets by suffixing a `scope` to this path e.g. - `/pushrules/global/`. This will return a subset of this data under the - specified key e.g. the `global` key. + Retrieve all push rulesets for this user. Currently the only push ruleset + defined is `global`. operationId: getPushRules security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: All the push rulesets for this user. @@ -43,214 +42,35 @@ paths: title: Ruleset allOf: - $ref: definitions/push_ruleset.yaml - examples: - response: - value: { - "global": { - "content": [ - { - "actions": [ - "notify", - { - "set_tweak": "sound", - "value": "default" - }, - { - "set_tweak": "highlight" - } - ], - "default": true, - "enabled": true, - "pattern": "alice", - "rule_id": ".m.rule.contains_user_name" - } - ], - "override": [ - { - "actions": [], - "conditions": [], - "default": true, - "enabled": false, - "rule_id": ".m.rule.master" - }, - { - "actions": [], - "conditions": [ - { - "key": "content.msgtype", - "kind": "event_match", - "pattern": "m.notice" - } - ], - "default": true, - "enabled": true, - "rule_id": ".m.rule.suppress_notices" - } - ], - "room": [], - "sender": [], - "underride": [ - { - "actions": [ - "notify", - { - "set_tweak": "sound", - "value": "ring" - }, - { - "set_tweak": "highlight", - "value": false - } - ], - "conditions": [ - { - "key": "type", - "kind": "event_match", - "pattern": "m.call.invite" - } - ], - "default": true, - "enabled": true, - "rule_id": ".m.rule.call" - }, - { - "actions": [ - "notify", - { - "set_tweak": "sound", - "value": "default" - }, - { - "set_tweak": "highlight" - } - ], - "conditions": [ - { - "kind": "contains_display_name" - } - ], - "default": true, - "enabled": true, - "rule_id": ".m.rule.contains_display_name" - }, - { - "actions": [ - "notify", - { - "set_tweak": "sound", - "value": "default" - }, - { - "set_tweak": "highlight", - "value": false - } - ], - "conditions": [ - { - "kind": "room_member_count", - "is": "2" - }, - { - "kind": "event_match", - "key": "type", - "pattern": "m.room.message" - } - ], - "default": true, - "enabled": true, - "rule_id": ".m.rule.room_one_to_one" - }, - { - "actions": [ - "notify", - { - "set_tweak": "sound", - "value": "default" - }, - { - "set_tweak": "highlight", - "value": false - } - ], - "conditions": [ - { - "key": "type", - "kind": "event_match", - "pattern": "m.room.member" - }, - { - "key": "content.membership", - "kind": "event_match", - "pattern": "invite" - }, - { - "key": "state_key", - "kind": "event_match", - "pattern": "@alice:example.com" - } - ], - "default": true, - "enabled": true, - "rule_id": ".m.rule.invite_for_me" - }, - { - "actions": [ - "notify", - { - "set_tweak": "highlight", - "value": false - } - ], - "conditions": [ - { - "key": "type", - "kind": "event_match", - "pattern": "m.room.member" - } - ], - "default": true, - "enabled": true, - "rule_id": ".m.rule.member_event" - }, - { - "actions": [ - "notify", - { - "set_tweak": "highlight", - "value": false - } - ], - "conditions": [ - { - "key": "type", - "kind": "event_match", - "pattern": "m.room.message" - } - ], - "default": true, - "enabled": true, - "rule_id": ".m.rule.message" - } - ] - } - } tags: - Push notifications - "/pushrules/{scope}/{kind}/{ruleId}": + /pushrules/global/: + get: + summary: Retrieve all push rules. + description: |- + Retrieve all push rules for this user. + operationId: getPushRulesGlobal + security: + - accessTokenQuery: [] + - accessTokenBearer: [] + responses: + "200": + description: All the push rules for this user. + content: + application/json: + schema: + $ref: definitions/push_ruleset.yaml + tags: + - Push notifications + "/pushrules/global/{kind}/{ruleId}": get: summary: Retrieve a push rule. description: Retrieve a single specified push rule. operationId: getPushRule security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - - in: path - name: scope - required: true - description: "`global` to specify global rules." - example: global - schema: - type: string - in: path name: kind required: true @@ -313,15 +133,9 @@ paths: description: This endpoint removes the push rule defined in the path. operationId: deletePushRule security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - - in: path - name: scope - required: true - description: "`global` to specify global rules." - example: global - schema: - type: string - in: path name: kind required: true @@ -389,15 +203,9 @@ paths: When creating push rules, they MUST be enabled by default. operationId: setPushRule security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - - in: path - name: scope - required: true - description: "`global` to specify global rules." - example: global - schema: - type: string - in: path name: kind required: true @@ -466,9 +274,7 @@ paths: rule to be applied to an event. A rule with no conditions always matches. Only applicable to `underride` and `override` rules. items: - type: object - allOf: - - $ref: definitions/push_condition.yaml + $ref: definitions/push_condition.yaml pattern: type: string description: Only applicable to `content` rules. The glob-style pattern to match @@ -521,23 +327,15 @@ paths: $ref: definitions/errors/rate_limited.yaml tags: - Push notifications - "/pushrules/{scope}/{kind}/{ruleId}/enabled": + "/pushrules/global/{kind}/{ruleId}/enabled": get: summary: Get whether a push rule is enabled description: This endpoint gets whether the specified push rule is enabled. operationId: isPushRuleEnabled security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - - in: path - name: scope - required: true - description: |- - Either `global` or `device/` to specify global - rules or device rules for the given `profile_tag`. - example: global - schema: - type: string - in: path name: kind required: true @@ -598,15 +396,9 @@ paths: push rule. operationId: setPushRuleEnabled security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - - in: path - name: scope - required: true - description: "`global` to specify global rules." - example: global - schema: - type: string - in: path name: kind required: true @@ -670,23 +462,15 @@ paths: } tags: - Push notifications - "/pushrules/{scope}/{kind}/{ruleId}/actions": + "/pushrules/global/{kind}/{ruleId}/actions": get: summary: The actions for a push rule description: This endpoint get the actions for the specified push rule. operationId: getPushRuleActions security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - - in: path - name: scope - required: true - description: |- - Either `global` or `device/` to specify global - rules or device rules for the given `profile_tag`. - example: global - schema: - type: string - in: path name: kind required: true @@ -756,15 +540,9 @@ paths: This can be used to change the actions of builtin rules. operationId: setPushRuleActions security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - - in: path - name: scope - required: true - description: "`global` to specify global rules." - example: global - schema: - type: string - in: path name: kind required: true @@ -849,4 +627,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/read_markers.yaml b/data/api/client-server/read_markers.yaml index 5372df34..ba2f4f0b 100644 --- a/data/api/client-server/read_markers.yaml +++ b/data/api/client-server/read_markers.yaml @@ -25,7 +25,8 @@ paths: the read receipt's location. operationId: setReadMarker security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -96,4 +97,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/receipts.yaml b/data/api/client-server/receipts.yaml index abbd7a62..c68ef3f6 100644 --- a/data/api/client-server/receipts.yaml +++ b/data/api/client-server/receipts.yaml @@ -25,7 +25,8 @@ paths: specified. operationId: postReceipt security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -132,4 +133,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/redaction.yaml b/data/api/client-server/redaction.yaml index aca69fa6..a61f01c4 100644 --- a/data/api/client-server/redaction.yaml +++ b/data/api/client-server/redaction.yaml @@ -33,7 +33,8 @@ paths: Server administrators may redact events sent by users on their server. operationId: redactEvent security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -103,4 +104,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/registration.yaml b/data/api/client-server/registration.yaml index 1f823ac8..1dd314b8 100644 --- a/data/api/client-server/registration.yaml +++ b/data/api/client-server/registration.yaml @@ -169,6 +169,7 @@ paths: x-addedInMatrixVersion: "1.3" home_server: type: string + deprecated: true description: |- The server_name of the homeserver on which the account has been registered. @@ -387,7 +388,9 @@ paths: access token provided in the request. Whether other access tokens for the user are revoked depends on the request parameters. security: - - accessToken: [] + - {} + - accessTokenQuery: [] + - accessTokenBearer: [] operationId: changePassword requestBody: content: @@ -591,7 +594,9 @@ paths: parameter because the homeserver is expected to sign the request to the identity server instead. security: - - accessToken: [] + - {} + - accessTokenQuery: [] + - accessTokenBearer: [] operationId: deactivateAccount requestBody: content: @@ -614,6 +619,26 @@ paths: it must return an `id_server_unbind_result` of `no-support`. example: example.org + erase: + x-addedInMatrixVersion: "1.10" + type: boolean + description: |- + Whether the user would like their content to be erased as + much as possible from the server. + + Erasure means that any users (or servers) which join the + room after the erasure request are served redacted copies of + the events sent by this account. Users which had visibility + on those events prior to the erasure are still able to see + unredacted copies. No redactions are sent and the erasure + request is not shared over federation, so other servers + might still serve unredacted copies. + + The server should additionally erase any non-event data + associated with the user, such as [account data](/client-server-api/#client-config) + and [contact 3PIDs](/client-server-api/#adding-account-administrative-contact-information). + + Defaults to `false` if not present. required: true responses: "200": @@ -737,3 +762,9 @@ servers: default: localhost:8008 basePath: default: /_matrix/client/v3 +components: + securitySchemes: + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/relations.yaml b/data/api/client-server/relations.yaml index 65c3491a..c4b0228c 100644 --- a/data/api/client-server/relations.yaml +++ b/data/api/client-server/relations.yaml @@ -1,4 +1,4 @@ -# Copyright 2022 The Matrix.org Foundation C.I.C. +# Copyright 2022,2024 The Matrix.org Foundation C.I.C. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -31,71 +31,16 @@ paths: page 1 and a `to` token from page 2 to paginate over the same range, however. operationId: getRelatingEvents security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - - in: path - name: roomId - description: The ID of the room containing the parent event. - required: true - example: "!636q39766251:matrix.org" - schema: - type: string - - in: path - name: eventId - description: The ID of the parent event whose child events are to be returned. - required: true - example: $asfDuShaf7Gafaw - schema: - type: string - - in: query - name: from - description: |- - The pagination token to start returning results from. If not supplied, results - start at the most recent topological event known to the server. - - Can be a `next_batch` or `prev_batch` token from a previous call, or a returned - `start` token from [`/messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages), - or a `next_batch` token from [`/sync`](/client-server-api/#get_matrixclientv3sync). - required: false - example: page2_token - schema: - type: string - - in: query - name: to - description: |- - The pagination token to stop returning results at. If not supplied, results - continue up to `limit` or until there are no more events. - - Like `from`, this can be a previous token from a prior call to this endpoint - or from `/messages` or `/sync`. - required: false - example: page3_token - schema: - type: string - - in: query - name: limit - description: |- - The maximum number of results to return in a single `chunk`. The server can - and should apply a maximum value to this parameter to avoid large responses. - - Similarly, the server should apply a default value when not supplied. - required: false - example: 20 - schema: - type: integer - - in: query - name: dir - x-addedInMatrixVersion: "1.4" - description: |- - Optional (default `b`) direction to return events from. If this is set to `f`, events - will be returned in chronological order starting at `from`. If it - is set to `b`, events will be returned in *reverse* chronological - order, again starting at `from`. - schema: - type: string - enum: - - b - - f + - $ref: '#/components/parameters/roomId' + - $ref: '#/components/parameters/eventId' + - $ref: '#/components/parameters/from' + - $ref: '#/components/parameters/to' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/dir' + - $ref: '#/components/parameters/recurse' responses: # note: this endpoint deliberately does not support rate limiting, therefore a # 429 error response is not included. @@ -107,60 +52,24 @@ paths: content: application/json: schema: - type: object - properties: - chunk: - title: ChildEventsChunk - type: array - description: The child events of the requested event, ordered topologically - most-recent first. - items: - allOf: - - $ref: definitions/client_event.yaml - next_batch: - type: string - description: |- - An opaque string representing a pagination token. The absence of this token - means there are no more results to fetch and the client should stop paginating. - prev_batch: - type: string - description: |- - An opaque string representing a pagination token. The absence of this token - means this is the start of the result set, i.e. this is the first batch/page. - required: - - chunk + allOf: + - $ref: '#/components/schemas/response' + - type: object + properties: + chunk: + title: ChildEventsChunk + type: array + description: The child events of the requested event, ordered topologically + most-recent first. + items: + $ref: definitions/client_event.yaml + required: + - chunk examples: response: - value: { - "chunk": [ - { - "room_id": "!636q39766251:matrix.org", - "$ref": "../../event-schemas/examples/m.room.message$m.text.yaml", - "content": { - "m.relates_to": { - "rel_type": "org.example.my_relation", - "event_id": "$asfDuShaf7Gafaw" - } - } - } - ], - "next_batch": "page2_token", - "prev_batch": "page1_token" - } + $ref: '#/components/examples/response' "404": - description: |- - The parent event was not found or the user does not have permission to read - this event (it might be contained in history that is not accessible to the user). - content: - application/json: - schema: - $ref: definitions/errors/error.yaml - examples: - response: - value: { - "errcode": "M_NOT_FOUND", - "error": "Event not found." - } + $ref: '#/components/responses/404' tags: - Event relationships # The same as above, with added `/{relType}` @@ -180,79 +89,17 @@ paths: page 1 and a `to` token from page 2 to paginate over the same range, however. operationId: getRelatingEventsWithRelType security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - - in: path - name: roomId - description: The ID of the room containing the parent event. - required: true - example: "!636q39766251:matrix.org" - schema: - type: string - - in: path - name: eventId - description: The ID of the parent event whose child events are to be returned. - required: true - example: $asfDuShaf7Gafaw - schema: - type: string - - in: path - name: relType - description: The [relationship type](/client-server-api/#relationship-types) to - search for. - required: true - example: org.example.my_relation - schema: - type: string - - in: query - name: from - description: |- - The pagination token to start returning results from. If not supplied, results - start at the most recent topological event known to the server. - - Can be a `next_batch` or `prev_batch` token from a previous call, or a returned - `start` token from [`/messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages), - or a `next_batch` token from [`/sync`](/client-server-api/#get_matrixclientv3sync). - required: false - example: page2_token - schema: - type: string - - in: query - name: to - description: |- - The pagination token to stop returning results at. If not supplied, results - continue up to `limit` or until there are no more events. - - Like `from`, this can be a previous token from a prior call to this endpoint - or from `/messages` or `/sync`. - required: false - example: page3_token - schema: - type: string - - in: query - name: limit - description: |- - The maximum number of results to return in a single `chunk`. The server can - and should apply a maximum value to this parameter to avoid large responses. - - Similarly, the server should apply a default value when not supplied. - required: false - example: 20 - schema: - type: integer - - in: query - name: dir - x-addedInMatrixVersion: "1.4" - description: |- - Optional (default `b`) direction to return events from. If this is set to `f`, events - will be returned in chronological order starting at `from`. If it - is set to `b`, events will be returned in *reverse* chronological - order, again starting at `from`. - schema: - type: string - enum: - - b - - f + - $ref: '#/components/parameters/roomId' + - $ref: '#/components/parameters/eventId' + - $ref: '#/components/parameters/relType' + - $ref: '#/components/parameters/from' + - $ref: '#/components/parameters/to' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/dir' + - $ref: '#/components/parameters/recurse' responses: # note: this endpoint deliberately does not support rate limiting, therefore a # 429 error response is not included. @@ -264,62 +111,26 @@ paths: content: application/json: schema: - type: object - properties: - chunk: - title: ChildEventsChunk - type: array - description: |- - The child events of the requested event, ordered topologically - most-recent first. The events returned will match the `relType` - supplied in the URL. - items: - allOf: - - $ref: definitions/client_event.yaml - next_batch: - type: string - description: |- - An opaque string representing a pagination token. The absence of this token - means there are no more results to fetch and the client should stop paginating. - prev_batch: - type: string - description: |- - An opaque string representing a pagination token. The absence of this token - means this is the start of the result set, i.e. this is the first batch/page. - required: - - chunk + allOf: + - $ref: '#/components/schemas/response' + - type: object + properties: + chunk: + title: ChildEventsChunk + type: array + description: |- + The child events of the requested event, ordered topologically + most-recent first. The events returned will match the `relType` + supplied in the URL. + items: + $ref: definitions/client_event.yaml + required: + - chunk examples: response: - value: { - "chunk": [ - { - "room_id": "!636q39766251:matrix.org", - "$ref": "../../event-schemas/examples/m.room.message$m.text.yaml", - "content": { - "m.relates_to": { - "rel_type": "org.example.my_relation", - "event_id": "$asfDuShaf7Gafaw" - } - } - } - ], - "next_batch": "page2_token", - "prev_batch": "page1_token" - } + $ref: '#/components/examples/response' "404": - description: |- - The parent event was not found or the user does not have permission to read - this event (it might be contained in history that is not accessible to the user). - content: - application/json: - schema: - $ref: definitions/errors/error.yaml - examples: - response: - value: { - "errcode": "M_NOT_FOUND", - "error": "Event not found." - } + $ref: '#/components/responses/404' tags: - Event relationships # The same as above, with added `/{eventType}` @@ -340,30 +151,12 @@ paths: page 1 and a `to` token from page 2 to paginate over the same range, however. operationId: getRelatingEventsWithRelTypeAndEventType security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - - in: path - name: roomId - description: The ID of the room containing the parent event. - required: true - example: "!636q39766251:matrix.org" - schema: - type: string - - in: path - name: eventId - description: The ID of the parent event whose child events are to be returned. - required: true - example: $asfDuShaf7Gafaw - schema: - type: string - - in: path - name: relType - description: The [relationship type](/client-server-api/#relationship-types) to - search for. - required: true - example: org.example.my_relation - schema: - type: string + - $ref: '#/components/parameters/roomId' + - $ref: '#/components/parameters/eventId' + - $ref: '#/components/parameters/relType' - in: path name: eventType description: |- @@ -375,55 +168,11 @@ paths: example: m.room.message schema: type: string - - in: query - name: from - description: |- - The pagination token to start returning results from. If not supplied, results - start at the most recent topological event known to the server. - - Can be a `next_batch` or `prev_batch` token from a previous call, or a returned - `start` token from [`/messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages), - or a `next_batch` token from [`/sync`](/client-server-api/#get_matrixclientv3sync). - required: false - example: page2_token - schema: - type: string - - in: query - name: to - description: |- - The pagination token to stop returning results at. If not supplied, results - continue up to `limit` or until there are no more events. - - Like `from`, this can be a previous token from a prior call to this endpoint - or from `/messages` or `/sync`. - required: false - example: page3_token - schema: - type: string - - in: query - name: limit - description: |- - The maximum number of results to return in a single `chunk`. The server can - and should apply a maximum value to this parameter to avoid large responses. - - Similarly, the server should apply a default value when not supplied. - required: false - example: 20 - schema: - type: integer - - in: query - name: dir - x-addedInMatrixVersion: "1.4" - description: |- - Optional (default `b`) direction to return events from. If this is set to `f`, events - will be returned in chronological order starting at `from`. If it - is set to `b`, events will be returned in *reverse* chronological - order, again starting at `from`. - schema: - type: string - enum: - - b - - f + - $ref: '#/components/parameters/from' + - $ref: '#/components/parameters/to' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/dir' + - $ref: '#/components/parameters/recurse' responses: # note: this endpoint deliberately does not support rate limiting, therefore a # 429 error response is not included. @@ -435,62 +184,26 @@ paths: content: application/json: schema: - type: object - properties: - chunk: - title: ChildEventsChunk - type: array - description: |- - The child events of the requested event, ordered topologically most-recent - first. The events returned will match the `relType` and `eventType` supplied - in the URL. - items: - allOf: - - $ref: definitions/client_event.yaml - next_batch: - type: string - description: |- - An opaque string representing a pagination token. The absence of this token - means there are no more results to fetch and the client should stop paginating. - prev_batch: - type: string - description: |- - An opaque string representing a pagination token. The absence of this token - means this is the start of the result set, i.e. this is the first batch/page. - required: - - chunk + allOf: + - $ref: '#/components/schemas/response' + - type: object + properties: + chunk: + title: ChildEventsChunk + type: array + description: |- + The child events of the requested event, ordered topologically most-recent + first. The events returned will match the `relType` and `eventType` supplied + in the URL. + items: + $ref: definitions/client_event.yaml + required: + - chunk examples: response: - value: { - "chunk": [ - { - "room_id": "!636q39766251:matrix.org", - "$ref": "../../event-schemas/examples/m.room.message$m.text.yaml", - "content": { - "m.relates_to": { - "rel_type": "org.example.my_relation", - "event_id": "$asfDuShaf7Gafaw" - } - } - } - ], - "next_batch": "page2_token", - "prev_batch": "page1_token" - } + $ref: '#/components/examples/response' "404": - description: |- - The parent event was not found or the user does not have permission to read - this event (it might be contained in history that is not accessible to the user). - content: - application/json: - schema: - $ref: definitions/errors/error.yaml - examples: - response: - value: { - "errcode": "M_NOT_FOUND", - "error": "Event not found." - } + $ref: '#/components/responses/404' tags: - Event relationships servers: @@ -507,4 +220,159 @@ servers: default: /_matrix/client/v1 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer + parameters: + roomId: + in: path + name: roomId + description: The ID of the room containing the parent event. + required: true + example: "!636q39766251:matrix.org" + schema: + type: string + eventId: + in: path + name: eventId + description: The ID of the parent event whose child events are to be returned. + required: true + example: $asfDuShaf7Gafaw + schema: + type: string + from: + in: query + name: from + description: |- + The pagination token to start returning results from. If not supplied, results + start at the most recent topological event known to the server. + + Can be a `next_batch` or `prev_batch` token from a previous call, or a returned + `start` token from [`/messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages), + or a `next_batch` token from [`/sync`](/client-server-api/#get_matrixclientv3sync). + required: false + example: page2_token + schema: + type: string + to: + in: query + name: to + description: |- + The pagination token to stop returning results at. If not supplied, results + continue up to `limit` or until there are no more events. + + Like `from`, this can be a previous token from a prior call to this endpoint + or from `/messages` or `/sync`. + required: false + example: page3_token + schema: + type: string + limit: + in: query + name: limit + description: |- + The maximum number of results to return in a single `chunk`. The server can + and should apply a maximum value to this parameter to avoid large responses. + + Similarly, the server should apply a default value when not supplied. + required: false + example: 20 + schema: + type: integer + dir: + in: query + name: dir + x-addedInMatrixVersion: "1.4" + description: |- + Optional (default `b`) direction to return events from. If this is set to `f`, events + will be returned in chronological order starting at `from`. If it + is set to `b`, events will be returned in *reverse* chronological + order, again starting at `from`. + schema: + type: string + enum: + - b + - f + relType: + in: path + name: relType + description: The [relationship type](/client-server-api/#relationship-types) to + search for. + required: true + example: org.example.my_relation + schema: + type: string + recurse: + in: query + name: recurse + x-addedInMatrixVersion: "1.10" + required: false + description: |- + Whether to additionally include events which only relate indirectly to the + given event, i.e. events related to the given event via two or more direct relationships. + + If set to `false`, only events which have a direct relation with the given + event will be included. + + If set to `true`, events which have an indirect relation with the given event + will be included additionally up to a certain depth level. Homeservers SHOULD traverse + at least 3 levels of relationships. Implementations MAY perform more but MUST be careful + to not infinitely recurse. + + The default value is `false`. + schema: + type: boolean + schemas: + response: + type: object + properties: + next_batch: + type: string + description: |- + An opaque string representing a pagination token. The absence of this token + means there are no more results to fetch and the client should stop paginating. + prev_batch: + type: string + description: |- + An opaque string representing a pagination token. The absence of this token + means this is the start of the result set, i.e. this is the first batch/page. + recursion_depth: + type: integer + description: |- + If the `recurse` parameter was supplied by the client, this response field is + mandatory and gives the actual depth to which the server recursed. If the client + did not specify the `recurse` parameter, this field must be absent. + responses: + "404": + description: |- + The parent event was not found or the user does not have permission to read + this event (it might be contained in history that is not accessible to the user). + content: + application/json: + schema: + $ref: definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_NOT_FOUND", + "error": "Event not found." + } + examples: + response: + value: { + "chunk": [ + { + "room_id": "!636q39766251:matrix.org", + "$ref": "../../event-schemas/examples/m.room.message$m.text.yaml", + "content": { + "m.relates_to": { + "rel_type": "org.example.my_relation", + "event_id": "$asfDuShaf7Gafaw" + } + } + } + ], + "next_batch": "page2_token", + "prev_batch": "page1_token" + } diff --git a/data/api/client-server/report_content.yaml b/data/api/client-server/report_content.yaml index 5ea7b634..654784ca 100644 --- a/data/api/client-server/report_content.yaml +++ b/data/api/client-server/report_content.yaml @@ -16,13 +16,85 @@ info: title: Matrix Client-Server Report Content API version: 1.0.0 paths: + "/rooms/{roomId}/report": + post: + x-addedInMatrixVersion: "1.13" + summary: Report a room as inappropriate. + description: |- + Reports a room as inappropriate to the server, which may then notify + the appropriate people. How such information is delivered is left up to + implementations. The caller is not required to be joined to the room to + report it. + operationId: reportRoom + parameters: + - in: path + name: roomId + description: The room being reported. + required: true + example: "!637q39766251:example.com" + schema: + type: string + requestBody: + content: + application/json: + schema: + type: object + example: { + "reason": "this makes me sad" + } + properties: + reason: + type: string + description: The reason the room is being reported. + required: true + security: + - accessTokenQuery: [] + - accessTokenBearer: [] + responses: + "200": + description: The room has been reported successfully. + content: + application/json: + schema: + type: object + examples: + response: + value: {} + "404": + description: |- + The room was not found on the homeserver. + content: + application/json: + schema: + $ref: definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_NOT_FOUND", + "error": "The room was not found." + } + "429": + description: This request was rate-limited. + content: + application/json: + schema: + $ref: definitions/errors/rate_limited.yaml + tags: + - Reporting content "/rooms/{roomId}/report/{eventId}": post: - summary: Reports an event as inappropriate. + summary: Report an event in a joined room as inappropriate. description: |- Reports an event as inappropriate to the server, which may then notify - the appropriate people. - operationId: reportContent + the appropriate people. The caller must be joined to the room to report + it. + + It might be possible for clients to deduce whether an event exists by + timing the response, as only a report for an event that does exist + will require the homeserver to check whether a user is joined to + the room. To combat this, homeserver implementations should add + a random delay when generating a response. + operationId: reportEvent parameters: - in: path name: roomId @@ -55,10 +127,14 @@ paths: and 0 is inoffensive. reason: type: string - description: The reason the content is being reported. May be blank. + description: The reason the content is being reported. required: true security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] + x-changedInMatrixVersion: + 1.8: | + This endpoint now requires the user to be joined to the room. responses: "200": description: The event has been reported successfully. @@ -69,6 +145,23 @@ paths: examples: response: value: {} + "404": + description: |- + The event was not found or you are not joined to the room where the + event resides. + + Homeserver implementations can additionally return this error if the + reported event has been redacted. + content: + application/json: + schema: + $ref: definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_NOT_FOUND", + "error": "The event was not found or you are not joined to the room." + } tags: - Reporting content servers: @@ -85,4 +178,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/room_event_by_timestamp.yaml b/data/api/client-server/room_event_by_timestamp.yaml index 19e7302b..1ab52cb9 100644 --- a/data/api/client-server/room_event_by_timestamp.yaml +++ b/data/api/client-server/room_event_by_timestamp.yaml @@ -30,7 +30,7 @@ paths: to ask other servers for a suitable event. After calling this endpoint, clients can call - [`/rooms/{roomId}/context/{eventId}`](#get_matrixclientv3roomsroomidcontexteventid) + [`/rooms/{roomId}/context/{eventId}`](/client-server-api/#get_matrixclientv3roomsroomidcontexteventid) to obtain a pagination token to retrieve the events around the returned event. The event returned by this endpoint could be an event that the client @@ -46,7 +46,8 @@ paths: found in that direction is outside of the expected range. operationId: getEventByTimestamp security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -136,4 +137,7 @@ servers: default: /_matrix/client/v1 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/room_initial_sync.yaml b/data/api/client-server/room_initial_sync.yaml index 53cb0bee..7b70bacb 100644 --- a/data/api/client-server/room_initial_sync.yaml +++ b/data/api/client-server/room_initial_sync.yaml @@ -15,7 +15,8 @@ paths: [migration guide](https://matrix.org/docs/guides/migrating-from-client-server-api-v-1#deprecated-endpoints). operationId: roomInitialSync security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -53,7 +54,7 @@ paths: type: string description: |- A token which correlates to the start of `chunk`. Can be passed to - [`/rooms//messages`](#get_matrixclientv3roomsroomidmessages) + [`/rooms//messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages) to retrieve earlier events. If no earlier events are available, this property may be omitted from @@ -62,7 +63,7 @@ paths: type: string description: |- A token which correlates to the end of `chunk`. Can be passed to - [`/rooms//messages`](#get_matrixclientv3roomsroomidmessages) + [`/rooms//messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages) to retrieve later events. chunk: type: array @@ -175,4 +176,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/room_send.yaml b/data/api/client-server/room_send.yaml index 638dc86d..25d8a75b 100644 --- a/data/api/client-server/room_send.yaml +++ b/data/api/client-server/room_send.yaml @@ -30,7 +30,8 @@ paths: [Room Events](/client-server-api/#room-events) for the m. event specification. operationId: sendMessage security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -110,4 +111,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/room_state.yaml b/data/api/client-server/room_state.yaml index 1c03dbdd..7096f511 100644 --- a/data/api/client-server/room_state.yaml +++ b/data/api/client-server/room_state.yaml @@ -39,7 +39,8 @@ paths: being removed or are already present in the state event. operationId: setRoomStateWithKey security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -142,4 +143,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/room_upgrades.yaml b/data/api/client-server/room_upgrades.yaml index 296ffe6a..5109a9b7 100644 --- a/data/api/client-server/room_upgrades.yaml +++ b/data/api/client-server/room_upgrades.yaml @@ -22,7 +22,8 @@ paths: description: Upgrades the given room to a particular room version. operationId: upgradeRoom security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -106,4 +107,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/rooms.yaml b/data/api/client-server/rooms.yaml index 4a192305..a2197f34 100644 --- a/data/api/client-server/rooms.yaml +++ b/data/api/client-server/rooms.yaml @@ -24,7 +24,8 @@ paths: retrieve this event e.g. by being a member in the room for this event. operationId: getOneRoomEvent security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -78,7 +79,8 @@ paths: taken from the state of the room when they left. operationId: getRoomStateWithKey security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -128,7 +130,8 @@ paths: description: Get the state events for the current state of a room. operationId: getRoomState security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -234,7 +237,8 @@ paths: - leave - ban security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: |- @@ -284,7 +288,8 @@ paths: schema: type: string security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: A map of MXID to room member objects. @@ -294,18 +299,20 @@ paths: type: object properties: joined: - additionalProperties: - title: RoomMember - type: object - properties: - display_name: - type: string - description: The display name of the user this object is representing. - avatar_url: - type: string - format: uri - description: The avatar of the user this object is representing, as an [`mxc://` - URI](/client-server-api/#matrix-content-mxc-uris). + patternProperties: + "^@": + x-pattern-format: mx-user-id + title: RoomMember + type: object + properties: + display_name: + type: string + description: The display name of the user this object is representing. + avatar_url: + type: string + format: uri + description: The avatar of the user this object is representing, as an [`mxc://` + URI](/client-server-api/#matrix-content-mxc-uris). description: A map from user ID to a RoomMember object. type: object examples: @@ -337,4 +344,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/search.yaml b/data/api/client-server/search.yaml index 981f93aa..587894ff 100644 --- a/data/api/client-server/search.yaml +++ b/data/api/client-server/search.yaml @@ -22,7 +22,8 @@ paths: description: Performs a full text search across different categories. operationId: search security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: next_batch @@ -224,19 +225,21 @@ paths: The historic profile information of the users that sent the events returned. - The `string` key is the user ID for which + The key is the user ID for which the profile belongs to. - additionalProperties: - type: object - title: User Profile - properties: - displayname: - type: string - title: Display name - avatar_url: - type: string - format: uri - title: Avatar Url + patternProperties: + "^@": + x-pattern-format: mx-user-id + type: object + title: User Profile + properties: + displayname: + type: string + title: Display name + avatar_url: + type: string + format: uri + title: Avatar Url events_before: type: array title: Events Before @@ -261,13 +264,15 @@ paths: This is included if the request had the `include_state` key set with a value of `true`. - The `string` key is the room ID for which the `State + The key is the room ID for which the `State Event` array belongs to. - additionalProperties: - type: array - title: Room State - items: - $ref: definitions/client_event.yaml + patternProperties: + "^!": + x-pattern-format: mx-room-id + type: array + title: Room State + items: + $ref: definitions/client_event.yaml groups: type: object title: Groups @@ -374,4 +379,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/space_hierarchy.yaml b/data/api/client-server/space_hierarchy.yaml index f7b98511..6329495c 100644 --- a/data/api/client-server/space_hierarchy.yaml +++ b/data/api/client-server/space_hierarchy.yaml @@ -26,11 +26,12 @@ paths: Where a child room is unknown to the local server, federation is used to fill in the details. The servers listed in the `via` array should be contacted to attempt to fill in missing rooms. - Only [`m.space.child`](#mspacechild) state events of the room are considered. Invalid child - rooms and parent events are not covered by this endpoint. + Only [`m.space.child`](/client-server-api/#mspacechild) state events of the room are considered. + Invalid child rooms and parent events are not covered by this endpoint. operationId: getSpaceHierarchy security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -43,8 +44,8 @@ paths: name: suggested_only description: |- Optional (default `false`) flag to indicate whether or not the server should only consider - suggested rooms. Suggested rooms are annotated in their [`m.space.child`](#mspacechild) event - contents. + suggested rooms. Suggested rooms are annotated in their [`m.space.child`](/client-server-api/#mspacechild) + event contents. example: true schema: type: boolean @@ -92,7 +93,7 @@ paths: allOf: - $ref: definitions/public_rooms_chunk.yaml - type: object - title: ChildRoomsChunk + title: SpaceHierarchyRoomsChunk properties: room_type: type: string @@ -102,8 +103,8 @@ paths: children_state: type: array description: |- - The [`m.space.child`](#mspacechild) events of the space-room, represented - as [Stripped State Events](#stripped-state) with an added `origin_server_ts` key. + The [`m.space.child`](/client-server-api/#mspacechild) events of the space-room, represented + as [Stripped State Events](/client-server-api/#stripped-state) with an added `origin_server_ts` key. If the room is not a space-room, this should be empty. items: @@ -216,4 +217,7 @@ servers: default: /_matrix/client/v1 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/support.yaml b/data/api/client-server/support.yaml new file mode 100644 index 00000000..b9ca062e --- /dev/null +++ b/data/api/client-server/support.yaml @@ -0,0 +1,139 @@ +# Copyright 2024 Kévin Commaille +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +openapi: 3.1.0 +info: + title: Matrix Client-Server Support Discovery API + version: 1.0.0 +paths: + /matrix/support: + get: + summary: Gets homeserver contacts and support details. + description: |- + Gets server admin contact and support page of the domain. + + Like the [well-known discovery URI](/client-server-api/#well-known-uri), + this should be accessed with the hostname of the homeserver by making a + GET request to `https://hostname/.well-known/matrix/support`. + + Note that this endpoint is not necessarily handled by the homeserver. + It may be served by another webserver, used for discovering support + information for the homeserver. + operationId: getWellknownSupport + x-addedInMatrixVersion: "1.10" + responses: + "200": + description: Server support information. + content: + application/json: + schema: + type: object + properties: + contacts: + type: array + description: |- + Ways to contact the server administrator. + + At least one of `contacts` or `support_page` is required. + If only `contacts` is set, it must contain at least one + item. + items: + type: object + title: Contact + description: A way to contact the server administrator. + properties: + matrix_id: + type: string + format: mx-user-id + pattern: "^@" + description: |- + A [Matrix User ID](/appendices/#user-identifiers) + representing the administrator. + + It could be an account registered on a different + homeserver so the administrator can be contacted + when the homeserver is down. + + At least one of `matrix_id` or `email_address` is + required. + email_address: + type: string + format: email + description: |- + An email address to reach the administrator. + + At least one of `matrix_id` or `email_address` is + required. + role: + type: string + enum: + - "m.role.admin" + - "m.role.security" + description: |- + An informal description of what the contact methods + are used for. + + `m.role.admin` is a catch-all role for any queries + and `m.role.security` is intended for sensitive + requests. + + Unspecified roles are permitted through the use of + [Namespaced Identifiers](/appendices/#common-namespaced-identifier-grammar). + required: + - role + example: { + "matrix_id": "@admin:example.org", + "email_address": "admin@example.org", + "role": "m.role.admin" + } + support_page: + type: string + format: uri + description: |- + The URL of a page to give users help specific to the + homeserver, like extra login/registration steps. + + At least one of `contacts` or `support_page` is required. + example: "https://example.org/support.html" + examples: + response: + value: + { + "contacts": [ + { + "matrix_id": "@admin:example.org", + "email_address": "admin@example.org", + "role": "m.role.admin" + }, + { + "email_address": "security@example.org", + "role": "m.role.security" + } + ], + "support_page": "https://example.org/support.html" + } + "404": + description: No server support information available. + tags: + - Server administration +servers: + - url: "{protocol}://{hostname}{basePath}" + variables: + protocol: + enum: + - https + default: https + hostname: + default: localhost:8008 + basePath: + default: /.well-known diff --git a/data/api/client-server/sync.yaml b/data/api/client-server/sync.yaml index 5e554722..9d9a807d 100644 --- a/data/api/client-server/sync.yaml +++ b/data/api/client-server/sync.yaml @@ -26,7 +26,8 @@ paths: incremental deltas to the state, and to receive new messages. *Note*: This endpoint supports lazy-loading. See [Filtering](/client-server-api/#filtering) - for more information. Lazy-loading members is only supported on a `StateFilter` + for more information. Lazy-loading members is only supported on the `state` part of a + [`RoomFilter`](#post_matrixclientv3useruseridfilter_request_roomfilter) for this endpoint. When lazy-loading is enabled, servers MUST include the syncing user's own membership event when they join a room, or when the full state of rooms is requested, to aid discovering the user's avatar & @@ -43,7 +44,8 @@ paths: events, alongside other state, when lazy-loading is not enabled. operationId: sync security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: filter @@ -140,223 +142,236 @@ paths: description: |- The rooms that the user has joined, mapped as room ID to room information. - additionalProperties: - title: Joined Room - type: object - properties: - summary: - title: RoomSummary - type: object - description: |- - Information about the room which clients may need to - correctly render it to users. - properties: - m.heroes: - type: array - description: |- - The users which can be used to generate a room name - if the room does not have one. Required if the room's - `m.room.name` or `m.room.canonical_alias` state events - are unset or empty. - - This should be the first 5 members of the room, ordered - by stream ordering, which are joined or invited. The - list must never include the client's own user ID. When - no joined or invited members are available, this should - consist of the banned and left users. More than 5 members - may be provided, however less than 5 should only be provided - when there are less than 5 members to represent. - - When lazy-loading room members is enabled, the membership - events for the heroes MUST be included in the `state`, - unless they are redundant. When the list of users changes, - the server notifies the client by sending a fresh list of - heroes. If there are no changes since the last sync, this - field may be omitted. - items: - type: string - m.joined_member_count: - type: integer - description: |- - The number of users with `membership` of `join`, - including the client's own user ID. If this field has - not changed since the last sync, it may be omitted. - Required otherwise. - m.invited_member_count: - type: integer - description: |- - The number of users with `membership` of `invite`. - If this field has not changed since the last sync, it - may be omitted. Required otherwise. - state: - title: State - type: object - description: |- - Updates to the state, between the time indicated by - the `since` parameter, and the start of the - `timeline` (or all state up to the start of the - `timeline`, if `since` is not given, or - `full_state` is true). - - N.B. state updates for `m.room.member` events will - be incomplete if `lazy_load_members` is enabled in - the `/sync` filter, and only return the member events - required to display the senders of the timeline events - in this response. - allOf: - - $ref: definitions/state_event_batch.yaml - timeline: - title: Timeline - type: object - description: |- - The timeline of messages and state changes in the - room. - allOf: - - $ref: definitions/timeline_batch.yaml - ephemeral: - title: Ephemeral - type: object - description: |- - The new ephemeral events in the room (events that - aren't recorded in the timeline or state of the - room). In this version of the spec, these are - [typing notification](#typing-notifications) and - [read receipt](#receipts) events. - allOf: - - $ref: definitions/event_batch.yaml - account_data: - title: Account Data - type: object - description: |- - The private data that this user has attached to - this room. - allOf: - - $ref: definitions/event_batch.yaml - unread_notifications: - title: Unread Notification Counts - type: object - description: |- - Counts of unread notifications for this room. See the - [Receiving notifications](/client-server-api/#receiving-notifications) section - for more information on how these are calculated. - - If `unread_thread_notifications` was specified as `true` on the `RoomEventFilter`, - these counts will only be for the main timeline rather than all events in the room. - See the [threading module](#threading) for more information. - x-changedInMatrixVersion: - "1.4": | - Updated to reflect behaviour of having `unread_thread_notifications` as `true` in - the `RoomEventFilter` for `/sync`. - properties: - highlight_count: - title: Highlighted notification count - type: integer - description: The number of unread notifications for this room with the highlight - flag set. - notification_count: - title: Total notification count - type: integer - description: The total number of unread notifications for this room. - unread_thread_notifications: - title: Unread Thread Notification Counts - type: object - description: |- - If `unread_thread_notifications` was specified as `true` on the `RoomEventFilter`, - the notification counts for each [thread](#threading) in this room. The object is - keyed by thread root ID, with values matching `unread_notifications`. - - If a thread does not have any notifications it can be omitted from this object. If - no threads have notification counts, this whole object can be omitted. - x-addedInMatrixVersion: "1.4" - additionalProperties: - title: ThreadNotificationCounts + patternProperties: + "^!": + x-pattern-format: mx-room-id + title: Joined Room + type: object + properties: + summary: + title: RoomSummary type: object + description: |- + Information about the room which clients may need to + correctly render it to users. + properties: + m.heroes: + type: array + description: |- + The users which can be used to generate a room name + if the room does not have one. Required if the room's + `m.room.name` or `m.room.canonical_alias` state events + are unset or empty. + + This should be the first 5 members of the room, ordered + by stream ordering, which are joined or invited. The + list must never include the client's own user ID. When + no joined or invited members are available, this should + consist of the banned and left users. More than 5 members + may be provided, however less than 5 should only be provided + when there are less than 5 members to represent. + + When lazy-loading room members is enabled, the membership + events for the heroes MUST be included in the `state`, + unless they are redundant. When the list of users changes, + the server notifies the client by sending a fresh list of + heroes. If there are no changes since the last sync, this + field may be omitted. + items: + type: string + m.joined_member_count: + type: integer + description: |- + The number of users with `membership` of `join`, + including the client's own user ID. If this field has + not changed since the last sync, it may be omitted. + Required otherwise. + m.invited_member_count: + type: integer + description: |- + The number of users with `membership` of `invite`. + If this field has not changed since the last sync, it + may be omitted. Required otherwise. + state: + title: State + type: object + description: |- + Updates to the state, between the time indicated by + the `since` parameter, and the start of the + `timeline` (or all state up to the start of the + `timeline`, if `since` is not given, or + `full_state` is true). + + N.B. state updates for `m.room.member` events will + be incomplete if `lazy_load_members` is enabled in + the `/sync` filter, and only return the member events + required to display the senders of the timeline events + in this response. + allOf: + - $ref: definitions/state_event_batch.yaml + timeline: + title: Timeline + type: object + description: |- + The timeline of messages and state changes in the + room. + allOf: + - $ref: definitions/timeline_batch.yaml + ephemeral: + title: Ephemeral + type: object + description: |- + The new ephemeral events in the room (events that + aren't recorded in the timeline or state of the + room). In this version of the spec, these are + [typing notification](/client-server-api/#typing-notifications) + and [read receipt](/client-server-api/#receipts) events. + allOf: + - $ref: definitions/event_batch.yaml + account_data: + title: Account Data + type: object + description: |- + The private data that this user has attached to + this room. + allOf: + - $ref: definitions/event_batch.yaml + unread_notifications: + title: Unread Notification Counts + type: object + description: |- + Counts of unread notifications for this room. See the + [Receiving notifications](/client-server-api/#receiving-notifications) section + for more information on how these are calculated. + + If `unread_thread_notifications` was specified as `true` on the `RoomEventFilter`, + these counts will only be for the main timeline rather than all events in the room. + See the [threading module](/client-server-api/#threading) for more information. + x-changedInMatrixVersion: + "1.4": | + Updated to reflect behaviour of having `unread_thread_notifications` as `true` in + the `RoomEventFilter` for `/sync`. properties: highlight_count: - title: ThreadedHighlightNotificationCount + title: Highlighted notification count type: integer - description: The number of unread notifications for this *thread* with the - highlight flag set. + description: The number of unread notifications for this room with the highlight + flag set. notification_count: - title: ThreadedTotalNotificationCount + title: Total notification count type: integer - description: The total number of unread notifications for this *thread*. + description: The total number of unread notifications for this room. + unread_thread_notifications: + title: Unread Thread Notification Counts + type: object + description: |- + If `unread_thread_notifications` was specified as `true` on the `RoomEventFilter`, + the notification counts for each [thread](/client-server-api/#threading) in this room. + The object is keyed by thread root ID, with values matching `unread_notifications`. + + If a thread does not have any notifications it can be omitted from this object. If + no threads have notification counts, this whole object can be omitted. + x-addedInMatrixVersion: "1.4" + patternProperties: + "^\\$": + x-pattern-format: mx-event-id + title: ThreadNotificationCounts + type: object + properties: + highlight_count: + title: ThreadedHighlightNotificationCount + type: integer + description: The number of unread notifications for this *thread* with the + highlight flag set. + notification_count: + title: ThreadedTotalNotificationCount + type: integer + description: The total number of unread notifications for this *thread*. invite: title: Invited Rooms type: object description: |- The rooms that the user has been invited to, mapped as room ID to room information. - additionalProperties: - title: Invited Room - type: object - properties: - invite_state: - title: InviteState - type: object - description: |- - The [stripped state](#stripped-state) of a room that the user has been invited - to. - properties: - events: - description: The [stripped state events](#stripped-state) that form the invite - state. - items: - $ref: ../../event-schemas/schema/core-event-schema/stripped_state.yaml - type: array + patternProperties: + "^!": + x-pattern-format: mx-room-id + title: Invited Room + type: object + properties: + invite_state: + title: InviteState + type: object + description: |- + The [stripped state](/client-server-api/#stripped-state) of a room that the user has + been invited to. + properties: + events: + description: |- + The [stripped state events](/client-server-api/#stripped-state) that form the + invite state. + items: + $ref: ../../event-schemas/schema/core-event-schema/stripped_state.yaml + type: array knock: title: Knocked rooms type: object description: The rooms that the user has knocked upon, mapped as room ID to room information. - additionalProperties: - title: Knocked Room - type: object - properties: - knock_state: - title: KnockState - type: object - description: The [stripped state](#stripped-state) of a room that the user has - knocked upon. - properties: - events: - description: The [stripped state events](#stripped-state) that form the knock - state. - items: - $ref: ../../event-schemas/schema/core-event-schema/stripped_state.yaml - type: array + patternProperties: + "^!": + x-pattern-format: mx-room-id + title: Knocked Room + type: object + properties: + knock_state: + title: KnockState + type: object + description: |- + The [stripped state](/client-server-api/#stripped-state) of a room that the user has + knocked upon. + properties: + events: + description: |- + The [stripped state events](/client-server-api/#stripped-state) that form the + knock state. + items: + $ref: ../../event-schemas/schema/core-event-schema/stripped_state.yaml + type: array leave: title: Left rooms type: object description: |- The rooms that the user has left or been banned from, mapped as room ID to room information. - additionalProperties: - title: Left Room - type: object - properties: - state: - title: State - type: object - description: The state updates for the room up to the start of the timeline. - allOf: - - $ref: definitions/state_event_batch.yaml - timeline: - title: Timeline - type: object - description: |- - The timeline of messages and state changes in the - room up to the point when the user left. - allOf: - - $ref: definitions/timeline_batch.yaml - account_data: - title: Account Data - type: object - description: |- - The private data that this user has attached to - this room. - allOf: - - $ref: definitions/event_batch.yaml + patternProperties: + "^!": + x-pattern-format: mx-room-id + title: Left Room + type: object + properties: + state: + title: State + type: object + description: The state updates for the room up to the start of the timeline. + allOf: + - $ref: definitions/state_event_batch.yaml + timeline: + title: Timeline + type: object + description: |- + The timeline of messages and state changes in the + room up to the point when the user left. + allOf: + - $ref: definitions/timeline_batch.yaml + account_data: + title: Account Data + type: object + description: |- + The private data that this user has attached to + this room. + allOf: + - $ref: definitions/event_batch.yaml presence: title: Presence type: object @@ -544,4 +559,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/tags.yaml b/data/api/client-server/tags.yaml index f805e02f..c8e1d78c 100644 --- a/data/api/client-server/tags.yaml +++ b/data/api/client-server/tags.yaml @@ -23,7 +23,8 @@ paths: description: List the tags set by a user on a room. operationId: getRoomTags security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -52,16 +53,7 @@ paths: tags: type: object additionalProperties: - title: Tag - type: object - properties: - order: - type: number - format: float - description: |- - A number in a range `[0,1]` describing a relative - position of the room under the given tag. - additionalProperties: true + $ref: definitions/tag.yaml examples: response: value: { @@ -83,7 +75,8 @@ paths: description: Add a tag to the room. operationId: setRoomTag security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -112,18 +105,7 @@ paths: content: application/json: schema: - type: object - properties: - order: - type: number - format: float - description: |- - A number in a range `[0,1]` describing a relative - position of the room under the given tag. - additionalProperties: true - example: { - "order": 0.25 - } + $ref: definitions/tag.yaml description: Extra data for the tag, e.g. ordering. required: true responses: @@ -143,7 +125,8 @@ paths: description: Remove a tag from the room. operationId: deleteRoomTag security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -194,4 +177,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/third_party_lookup.yaml b/data/api/client-server/third_party_lookup.yaml index 797f065f..3055b8ae 100644 --- a/data/api/client-server/third_party_lookup.yaml +++ b/data/api/client-server/third_party_lookup.yaml @@ -25,7 +25,8 @@ paths: required for queries against each protocol. operationId: getProtocols security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: The protocols supported by the homeserver. @@ -42,7 +43,8 @@ paths: third-party protocol. operationId: getProtocolMetadata security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: protocol @@ -85,7 +87,8 @@ paths: as reasonably possible given the network type. operationId: queryLocationByProtocol security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: protocol @@ -95,12 +98,14 @@ paths: schema: type: string - in: query - name: searchFields + name: fields description: |- One or more custom fields to help identify the third-party location. schema: - type: string + type: object + additionalProperties: + type: string responses: "200": description: At least one portal room was found. @@ -129,7 +134,8 @@ paths: a set of user parameters. operationId: queryUserByProtocol security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: protocol @@ -154,7 +160,7 @@ paths: schema: $ref: ../application-service/definitions/user_batch.yaml "404": - description: The Matrix User ID was not found + description: The Matrix User ID was not found. content: application/json: schema: @@ -174,7 +180,8 @@ paths: alias. operationId: queryLocationByAlias security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: alias @@ -209,7 +216,8 @@ paths: description: Retrieve an array of third-party users from a Matrix User ID. operationId: queryUserByID security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: userid @@ -226,7 +234,7 @@ paths: schema: $ref: ../application-service/definitions/user_batch.yaml "404": - description: The Matrix User ID was not found + description: The Matrix User ID was not found. content: application/json: schema: @@ -252,4 +260,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/third_party_membership.yaml b/data/api/client-server/third_party_membership.yaml index 7105ac84..ea366648 100644 --- a/data/api/client-server/third_party_membership.yaml +++ b/data/api/client-server/third_party_membership.yaml @@ -62,7 +62,8 @@ paths: append a `m.room.third_party_invite` event to the room. operationId: inviteBy3PID security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -157,4 +158,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/threads_list.yaml b/data/api/client-server/threads_list.yaml index 8724b58d..1f16dde2 100644 --- a/data/api/client-server/threads_list.yaml +++ b/data/api/client-server/threads_list.yaml @@ -27,7 +27,8 @@ paths: user has participated in the thread. operationId: getThreadRoots security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: roomId @@ -160,4 +161,7 @@ servers: default: /_matrix/client/v1 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/to_device.yaml b/data/api/client-server/to_device.yaml index d8832fa3..cea23ab7 100644 --- a/data/api/client-server/to_device.yaml +++ b/data/api/client-server/to_device.yaml @@ -24,7 +24,8 @@ paths: client devices. operationId: sendToDevice security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: eventType @@ -56,12 +57,14 @@ paths: The messages to send. A map from user ID, to a map from device ID to message body. The device ID may also be `*`, meaning all known devices for the user. - additionalProperties: - type: object - additionalProperties: + patternProperties: + "^@": + x-pattern-format: mx-user-id type: object - title: EventContent - description: Message content + additionalProperties: + type: object + title: EventContent + description: Message content example: "@alice:example.com": TLLBEANAAG: @@ -95,4 +98,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/typing.yaml b/data/api/client-server/typing.yaml index 6d6a7437..0d21f452 100644 --- a/data/api/client-server/typing.yaml +++ b/data/api/client-server/typing.yaml @@ -26,7 +26,8 @@ paths: user has stopped typing. operationId: setTyping security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: path name: userId @@ -96,4 +97,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/users.yaml b/data/api/client-server/users.yaml index 67854f08..3a7f2bfa 100644 --- a/data/api/client-server/users.yaml +++ b/data/api/client-server/users.yaml @@ -32,7 +32,8 @@ paths: `Accept-Language` header provided in the request, if present. operationId: searchUserDirectory security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -122,4 +123,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/versions.yaml b/data/api/client-server/versions.yaml index 14785e53..bf4353f2 100644 --- a/data/api/client-server/versions.yaml +++ b/data/api/client-server/versions.yaml @@ -34,11 +34,22 @@ paths: which has not yet landed in the spec. For example, a feature currently undergoing the proposal process may appear here and eventually be taken off this list once the feature lands in the spec and the server deems it - reasonable to do so. Servers may wish to keep advertising features here - after they've been released into the spec to give clients a chance to - upgrade appropriately. Additionally, clients should avoid using unstable - features in their stable releases. + reasonable to do so. Servers can choose to enable some features only for + some users, so clients should include authentication in the request to + get all the features available for the logged-in user. If no + authentication is provided, the server should only return the features + available to all users. Servers may wish to keep advertising features + here after they've been released into the spec to give clients a chance + to upgrade appropriately. Additionally, clients should avoid using + unstable features in their stable releases. operationId: getVersions + security: + - {} + - accessTokenQuery: [] + - accessTokenBearer: [] + x-changedInMatrixVersion: + "1.10": | + This endpoint can behave differently when authentication is provided. responses: "200": description: The versions supported by the server. @@ -89,3 +100,9 @@ servers: default: localhost:8008 basePath: default: /_matrix/client +components: + securitySchemes: + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/voip.yaml b/data/api/client-server/voip.yaml index ea9146ec..4466e36c 100644 --- a/data/api/client-server/voip.yaml +++ b/data/api/client-server/voip.yaml @@ -24,7 +24,8 @@ paths: calls. operationId: getTurnServer security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: The TURN server credentials. @@ -86,4 +87,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/client-server/whoami.yaml b/data/api/client-server/whoami.yaml index 342cbeb7..8f4027e7 100644 --- a/data/api/client-server/whoami.yaml +++ b/data/api/client-server/whoami.yaml @@ -30,7 +30,8 @@ paths: body. operationId: getTokenOwner security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: The token belongs to a known user. @@ -56,9 +57,9 @@ paths: x-addedInMatrixVersion: "1.2" type: boolean description: |- - When `true`, the user is a [Guest User](#guest-access). When - not present or `false`, the user is presumed to be a non-guest - user. + When `true`, the user is a [Guest User](/client-server-api/#guest-access). + When not present or `false`, the user is presumed to be a + non-guest user. examples: response: value: { @@ -112,4 +113,7 @@ servers: default: /_matrix/client/v3 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/identity/definitions/security.yaml b/data/api/identity/definitions/security.yaml index 64225ec4..598005b7 100644 --- a/data/api/identity/definitions/security.yaml +++ b/data/api/identity/definitions/security.yaml @@ -11,8 +11,18 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -accessToken: +accessTokenQuery: type: apiKey - description: The access_token returned by a call to `/register`. + description: |- + **Deprecated.** The `access_token` returned by a call to `/register`, as a + query parameter. name: access_token in: query +accessTokenBearer: + type: http + description: |- + The `access_token` returned by a call to `/register`, using the + `Authorization: Bearer` header. + + This is the preferred method. + scheme: bearer diff --git a/data/api/identity/v2_associations.yaml b/data/api/identity/v2_associations.yaml index c9b8ba6e..73de676e 100644 --- a/data/api/identity/v2_associations.yaml +++ b/data/api/identity/v2_associations.yaml @@ -23,7 +23,8 @@ paths: description: Determines if a given 3pid has been validated by a user. operationId: getValidated3pidV2 security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: sid @@ -128,7 +129,8 @@ paths: deprecated. operationId: bindV2 security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -279,7 +281,8 @@ paths: homeserver is acting on behalf of a client. operationId: unbindV2 security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -383,4 +386,7 @@ servers: default: /_matrix/identity/v2 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/identity/v2_auth.yaml b/data/api/identity/v2_auth.yaml index 64433f81..cb41cdab 100644 --- a/data/api/identity/v2_auth.yaml +++ b/data/api/identity/v2_auth.yaml @@ -58,7 +58,8 @@ paths: request. operationId: getAccount security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: The token holder's information. @@ -99,7 +100,8 @@ paths: future requests to the server. operationId: logout security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: The token was successfully logged out. @@ -150,4 +152,7 @@ servers: default: /_matrix/identity/v2 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/identity/v2_email_associations.yaml b/data/api/identity/v2_email_associations.yaml index ad5c2517..81f4486c 100644 --- a/data/api/identity/v2_email_associations.yaml +++ b/data/api/identity/v2_email_associations.yaml @@ -40,7 +40,8 @@ paths: deprecated. operationId: emailRequestTokenV2 security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -107,7 +108,8 @@ paths: deprecated. operationId: emailSubmitTokenPostV2 security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -180,7 +182,8 @@ paths: used by end-users, and so the response should be human-readable. operationId: emailSubmitTokenGetV2 security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: sid @@ -242,4 +245,7 @@ servers: default: /_matrix/identity/v2 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/identity/v2_invitation_signing.yaml b/data/api/identity/v2_invitation_signing.yaml index ae05c6fd..104cafd6 100644 --- a/data/api/identity/v2_invitation_signing.yaml +++ b/data/api/identity/v2_invitation_signing.yaml @@ -27,7 +27,8 @@ paths: to `store-invite`, and fetch the sender of the invite. operationId: blindlySignStuffV2 security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -132,4 +133,7 @@ servers: default: /_matrix/identity/v2 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/identity/v2_lookup.yaml b/data/api/identity/v2_lookup.yaml index ce716abd..e3c7985f 100644 --- a/data/api/identity/v2_lookup.yaml +++ b/data/api/identity/v2_lookup.yaml @@ -28,7 +28,8 @@ paths: any of the algorithms defined in this specification. operationId: getHashDetails security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] responses: "200": description: The hash function information. @@ -70,7 +71,8 @@ paths: later in this specification. operationId: lookupUsersV2 security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -162,4 +164,7 @@ servers: default: /_matrix/identity/v2 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/identity/v2_phone_associations.yaml b/data/api/identity/v2_phone_associations.yaml index 7f44fb3d..b985a972 100644 --- a/data/api/identity/v2_phone_associations.yaml +++ b/data/api/identity/v2_phone_associations.yaml @@ -40,7 +40,8 @@ paths: deprecated. operationId: msisdnRequestTokenV2 security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -109,7 +110,8 @@ paths: deprecated. operationId: msisdnSubmitTokenPostV2 security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -182,7 +184,8 @@ paths: used by end-users, and so the response should be human-readable. operationId: msisdnSubmitTokenGetV2 security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] parameters: - in: query name: sid @@ -243,4 +246,7 @@ servers: default: /_matrix/identity/v2 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/identity/v2_store_invite.yaml b/data/api/identity/v2_store_invite.yaml index 230dd503..5dcd9a78 100644 --- a/data/api/identity/v2_store_invite.yaml +++ b/data/api/identity/v2_store_invite.yaml @@ -51,7 +51,8 @@ paths: the `address` of the pending invite for display purposes. operationId: storeInviteV2 security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -224,4 +225,7 @@ servers: default: /_matrix/identity/v2 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/identity/v2_terms.yaml b/data/api/identity/v2_terms.yaml index 550d0bdb..d7c231d4 100644 --- a/data/api/identity/v2_terms.yaml +++ b/data/api/identity/v2_terms.yaml @@ -52,7 +52,6 @@ paths: might be and could be "alpha", semantically versioned, or arbitrary. required: - version - # TODO: TravisR - Make this render additionalProperties: type: object title: Internationalised Policy @@ -119,7 +118,8 @@ paths: may not be accepting all terms at once. operationId: agreeToTerms security: - - accessToken: [] + - accessTokenQuery: [] + - accessTokenBearer: [] requestBody: content: application/json: @@ -159,4 +159,7 @@ servers: default: /_matrix/identity/v2 components: securitySchemes: - $ref: definitions/security.yaml + accessTokenQuery: + $ref: definitions/security.yaml#/accessTokenQuery + accessTokenBearer: + $ref: definitions/security.yaml#/accessTokenBearer diff --git a/data/api/push-gateway/push_notifier.yaml b/data/api/push-gateway/push_notifier.yaml index e23d33b0..9f461a1c 100644 --- a/data/api/push-gateway/push_notifier.yaml +++ b/data/api/push-gateway/push_notifier.yaml @@ -35,9 +35,9 @@ paths: updating counts of unread notifications should be idempotent and therefore do not require duplicate suppression. - Notifications are sent to the URL configured when the pusher is created. - This means that the HTTP path may be different depending on the push - gateway. + Clients interested in receiving notifications via this endpoint MUST + configure its full URI when creating the associated pusher via + [`/_matrix/client/v3/pushers/set`](/client-server-api/#post_matrixclientv3pushersset). operationId: notify requestBody: content: @@ -182,9 +182,15 @@ paths: type: object title: PusherData description: |- - A dictionary of additional pusher-specific data. For - 'http' pushers, this is the data dictionary passed in at - pusher creation minus the `url` key. + A dictionary of additional pusher-specific data. This + is the `data` dictionary passed in at + [pusher creation](/client-server-api/#post_matrixclientv3pushersset) + minus the `url` key. + properties: + format: + type: string + description: |- + The format to use for sending notifications. tweaks: type: object title: Tweaks diff --git a/data/api/server-server/backfill.yaml b/data/api/server-server/backfill.yaml index a37e5ed4..ddcc6ab0 100644 --- a/data/api/server-server/backfill.yaml +++ b/data/api/server-server/backfill.yaml @@ -162,4 +162,5 @@ servers: default: /_matrix/federation/v1 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/content_repository.yaml b/data/api/server-server/content_repository.yaml new file mode 100644 index 00000000..66439b79 --- /dev/null +++ b/data/api/server-server/content_repository.yaml @@ -0,0 +1,303 @@ +# Copyright 2024 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +openapi: 3.1.0 +info: + title: Matrix Federation Content Repository API + version: 1.0.0 +paths: + "/media/download/{mediaId}": + get: + x-addedInMatrixVersion: "1.11" + summary: Download content from the content repository. + operationId: getContent + security: + - signedRequest: [] + parameters: + - $ref: '#/components/parameters/mediaId' + - $ref: '#/components/parameters/timeout_ms' + responses: + "200": + description: The content that was previously uploaded. + headers: + Content-Type: + $ref: '#/components/headers/downloadContentType' + content: + multipart/mixed: + schema: + # This is a workaround for us not being able to say the response is required. + description: |- + **Required.** MUST contain a `boundary` (per [RFC 2046](https://datatracker.ietf.org/doc/html/rfc2046#section-5.1)) + delineating exactly two parts: + + The first part has a `Content-Type` header of `application/json` + and describes the media's metadata, if any. Currently, this will + always be an empty object. + + The second part is either: + + 1. the bytes of the media itself, using `Content-Type` and + `Content-Disposition` headers as appropriate; + 2. or a `Location` header to redirect the caller to where the media + can be retrieved. The URL at `Location` SHOULD have appropriate + `Content-Type` and `Content-Disposition` headers which describe + the media. + + When `Location` is present, servers SHOULD NOT cache the URL. + The remote server may have applied time limits on its validity. + If the caller requires an up-to-date URL, it SHOULD re-request + the media download. + "429": + $ref: '#/components/responses/rateLimited' + "502": + description: The content is too large for the server to serve. + content: + application/json: + schema: + # XXX: We should move error definitions into a more generic place. + $ref: ../client-server/definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_TOO_LARGE", + "error": "Content is too large to serve" + } + "504": + $ref: '#/components/responses/notYetUploaded' + tags: + - Media + "/media/thumbnail/{mediaId}": + get: + x-addedInMatrixVersion: "1.11" + summary: Download a thumbnail of content from the content repository + description: |- + Download a thumbnail of content from the content repository. + See the [Client-Server API Thumbnails](/client-server-api/#thumbnails) + section for more information. + operationId: getContentThumbnail + security: + - signedRequest: [] + parameters: + - $ref: '#/components/parameters/mediaId' + - in: query + name: width + required: true + description: |- + The *desired* width of the thumbnail. The actual thumbnail may be + larger than the size specified. + example: 64 + schema: + type: integer + - in: query + name: height + required: true + description: |- + The *desired* height of the thumbnail. The actual thumbnail may be + larger than the size specified. + example: 64 + schema: + type: integer + - in: query + name: method + description: |- + The desired resizing method. See the [Client-Server API Thumbnails](/client-server-api/#thumbnails) + section for more information. + example: scale + schema: + type: string + enum: + - crop + - scale + - $ref: '#/components/parameters/timeout_ms' + - in: query + name: animated + x-addedInMatrixVersion: "1.11" + required: false + description: | + Indicates preference for an animated thumbnail from the server, if possible. Animated + thumbnails typically use the content types `image/gif`, `image/png` (with APNG format), + `image/apng`, and `image/webp` instead of the common static `image/png` or `image/jpeg` + content types. + + When `true`, the server SHOULD return an animated thumbnail if possible and supported. + When `false`, the server MUST NOT return an animated thumbnail. For example, returning a + static `image/png` or `image/jpeg` thumbnail. When not provided, the server SHOULD NOT + return an animated thumbnail. + + Servers SHOULD prefer to return `image/webp` thumbnails when supporting animation. + + When `true` and the media cannot be animated, such as in the case of a JPEG or PDF, the + server SHOULD behave as though `animated` is `false`. + example: false + schema: + type: boolean + responses: + "200": + description: A thumbnail of the requested content. + headers: + Content-Type: + description: Must be `multipart/mixed`. + schema: + type: string + content: + multipart/mixed: + schema: + # This is a workaround for us not being able to say the response is required. + description: |- + **Required.** MUST contain a `boundary` (per [RFC 2046](https://datatracker.ietf.org/doc/html/rfc2046#section-5.1)) + delineating exactly two parts: + + The first part has a `Content-Type` header of `application/json` + and describes the media's metadata, if any. Currently, this will + always be an empty object. + + The second part is either: + + 1. the bytes of the media itself, using `Content-Type` and + `Content-Disposition` headers as appropriate; + 2. or a `Location` header to redirect the caller to where the media + can be retrieved. The URL at `Location` SHOULD have appropriate + `Content-Type` and `Content-Disposition` headers which describe + the media. + + When `Location` is present, servers SHOULD NOT cache the URL. + The remote server may have applied time limits on its validity. + If the caller requires an up-to-date URL, it SHOULD re-request + the media download. + + {{% boxes/note %}} + The `Content-Type` for the second part SHOULD be one of: + * `image/png` (possibly of the APNG variety) + * `image/apng` + * `image/jpeg` + * `image/gif` + * `image/webp` + {{% /boxes/note %}} + "400": + description: |- + The request does not make sense to the server, or the server cannot thumbnail + the content. For example, the caller requested non-integer dimensions or asked + for negatively-sized images. + content: + application/json: + schema: + # XXX: We should move error definitions into a more generic place. + $ref: ../client-server/definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_UNKNOWN", + "error": "Cannot generate thumbnails for the requested content" + } + "413": + description: The local content is too large for the server to thumbnail. + content: + application/json: + schema: + # XXX: We should move error definitions into a more generic place. + $ref: ../client-server/definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_TOO_LARGE", + "error": "Content is too large to thumbnail" + } + "429": + $ref: '#/components/responses/rateLimited' + "502": + description: The remote content is too large for the server to thumbnail. + content: + application/json: + schema: + # XXX: We should move error definitions into a more generic place. + $ref: ../client-server/definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_TOO_LARGE", + "error": "Content is too large to thumbnail" + } + "504": + $ref: '#/components/responses/notYetUploaded' + tags: + - Media +servers: + - url: "{protocol}://{hostname}{basePath}" + variables: + protocol: + enum: + - http + - https + default: https + hostname: + default: localhost:8448 + basePath: + default: /_matrix/federation/v1 +components: + securitySchemes: + signedRequest: + $ref: definitions/security.yaml#/signedRequest + parameters: + mediaId: + in: path + name: mediaId + required: true + description: | + The media ID from the `mxc://` URI (the path component). + example: ascERGshawAWawugaAcauga + schema: + type: string + timeout_ms: + in: query + name: timeout_ms + x-addedInMatrixVersion: "1.7" + description: | + The maximum number of milliseconds that the client is willing to wait to + start receiving data, in the case that the content has not yet been + uploaded. The default value is 20000 (20 seconds). The content + repository SHOULD impose a maximum value for this parameter. The + content repository MAY respond before the timeout. + example: 5000 + schema: + type: integer + format: int64 + default: 20000 + responses: + rateLimited: + description: This request was rate-limited. + content: + application/json: + schema: + # XXX: We should move error definitions into a more generic place. + $ref: ../client-server/definitions/errors/rate_limited.yaml + notYetUploaded: + description: |- + The content is not yet available. A [standard error response](/client-server-api/#standard-error-response) + will be returned with the `errcode` `M_NOT_YET_UPLOADED`. + content: + application/json: + schema: + # XXX: We should move error definitions into a more generic place. + $ref: ../client-server/definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_NOT_YET_UPLOADED", + "error": "Content has not yet been uploaded" + } + headers: + downloadContentType: + description: |- + Must be `multipart/mixed`. + schema: + type: string diff --git a/data/api/server-server/definitions/event-schemas/m.device_list_update.yaml b/data/api/server-server/definitions/event-schemas/m.device_list_update.yaml index 81519e66..8bb8a7dd 100644 --- a/data/api/server-server/definitions/event-schemas/m.device_list_update.yaml +++ b/data/api/server-server/definitions/event-schemas/m.device_list_update.yaml @@ -31,7 +31,7 @@ allOf: - type: object properties: edu_type: - type: enum + type: string enum: ['m.device_list_update'] description: The string `m.device_list_update`. example: "m.device_list_update" diff --git a/data/api/server-server/definitions/event-schemas/m.direct_to_device.yaml b/data/api/server-server/definitions/event-schemas/m.direct_to_device.yaml index f628ebe0..3740eace 100644 --- a/data/api/server-server/definitions/event-schemas/m.direct_to_device.yaml +++ b/data/api/server-server/definitions/event-schemas/m.direct_to_device.yaml @@ -23,7 +23,7 @@ allOf: - type: object properties: edu_type: - type: enum + type: string enum: ['m.direct_to_device'] description: The string `m.direct_to_device`. example: "m.direct_to_device" @@ -51,13 +51,15 @@ allOf: The contents of the messages to be sent. These are arranged in a map of user IDs to a map of device IDs to message bodies. The device ID may also be `*`, meaning all known devices for the user. - additionalProperties: - type: object - title: User Devices - additionalProperties: + patternProperties: + "^@": + x-pattern-format: mx-user-id type: object - title: Device Message Contents - properties: {} + title: User Devices + additionalProperties: + type: object + title: Device Message Contents + properties: {} example: { "@alice:example.org": { "IWHQUZUIAH": { diff --git a/data/api/server-server/definitions/event-schemas/m.presence.yaml b/data/api/server-server/definitions/event-schemas/m.presence.yaml index 09d5d0d2..c79729e0 100644 --- a/data/api/server-server/definitions/event-schemas/m.presence.yaml +++ b/data/api/server-server/definitions/event-schemas/m.presence.yaml @@ -21,7 +21,7 @@ allOf: - type: object properties: edu_type: - type: enum + type: string enum: ['m.presence'] description: The string `m.presence` example: "m.presence" @@ -44,7 +44,7 @@ allOf: description: The user ID this presence EDU is for. example: "@john:matrix.org" presence: - type: enum + type: string enum: ['offline', 'unavailable', 'online'] description: The presence of the user. example: "online" diff --git a/data/api/server-server/definitions/event-schemas/m.receipt.yaml b/data/api/server-server/definitions/event-schemas/m.receipt.yaml index bbc3ac67..60bff325 100644 --- a/data/api/server-server/definitions/event-schemas/m.receipt.yaml +++ b/data/api/server-server/definitions/event-schemas/m.receipt.yaml @@ -24,7 +24,7 @@ allOf: - type: object properties: edu_type: - type: enum + type: string enum: ['m.receipt'] description: The string `m.receipt` example: "m.receipt" @@ -33,50 +33,58 @@ allOf: description: |- Receipts for a particular room. The string key is the room ID for which the receipts under it belong. - additionalProperties: - type: object - title: Room Receipts - properties: - # We strongly define the receipt type to help spec future ones later - # on. At that point, m.read can become optional (maybe). - "m.read": - type: object - description: Read receipts for users in the room. - title: User Read Receipt - properties: - event_ids: - type: array - description: |- - The extremity event IDs that the user has read up to. - minItems: 1 - maxItems: 1 - items: - type: string - example: ['$read_this_event:matrix.org'] - data: - type: object - description: Metadata for the read receipt. - title: Read Receipt Metadata - properties: - ts: - type: integer - format: int64 - description: |- - A POSIX timestamp in milliseconds for when the user read - the event specified in the read receipt. - example: 1533358089009 - thread_id: - type: string - x-addedInMatrixVersion: "1.4" + patternProperties: + "^!": + x-pattern-format: mx-room-id + type: object + title: Room Receipts + properties: + # We strongly define the receipt type to help spec future ones later + # on. At that point, m.read can become optional (maybe). + "m.read": + type: object + description: |- + Read receipts for users in the room. The string key is the user + ID the receipt belongs to. + patternProperties: + "^@": + x-pattern-format: mx-user-id + type: object + title: User Read Receipt + properties: + event_ids: + type: array description: |- - The root thread event's ID (or `main`) for which - thread this receipt is intended to be under. If - not specified, the read receipt is *unthreaded* - (default). - example: "$threadroot" - required: ['ts'] - required: ['event_ids', 'data'] - required: ['m.read'] + The extremity event IDs that the user has read up to. + minItems: 1 + maxItems: 1 + items: + type: string + example: ['$read_this_event:matrix.org'] + data: + type: object + description: Metadata for the read receipt. + title: Read Receipt Metadata + properties: + ts: + type: integer + format: int64 + description: |- + A POSIX timestamp in milliseconds for when the user read + the event specified in the read receipt. + example: 1533358089009 + thread_id: + type: string + x-addedInMatrixVersion: "1.4" + description: |- + The root thread event's ID (or `main`) for which + thread this receipt is intended to be under. If + not specified, the read receipt is *unthreaded* + (default). + example: "$threadroot" + required: ['ts'] + required: ['event_ids', 'data'] + required: ['m.read'] example: { "!some_room:example.org": { "m.read": { diff --git a/data/api/server-server/definitions/event-schemas/m.signing_key_update.yaml b/data/api/server-server/definitions/event-schemas/m.signing_key_update.yaml index aea99fe0..0748bc35 100644 --- a/data/api/server-server/definitions/event-schemas/m.signing_key_update.yaml +++ b/data/api/server-server/definitions/event-schemas/m.signing_key_update.yaml @@ -23,7 +23,7 @@ allOf: - type: object properties: edu_type: - type: enum + type: string enum: ['m.signing_key_update'] description: The string `m.signing_update`. example: "m.signing_key_update" diff --git a/data/api/server-server/definitions/event-schemas/m.typing.yaml b/data/api/server-server/definitions/event-schemas/m.typing.yaml index 7f23bae1..fa36a871 100644 --- a/data/api/server-server/definitions/event-schemas/m.typing.yaml +++ b/data/api/server-server/definitions/event-schemas/m.typing.yaml @@ -20,7 +20,7 @@ allOf: - type: object properties: edu_type: - type: enum + type: string enum: ['m.typing'] description: The string `m.typing` example: "m.typing" diff --git a/data/api/server-server/definitions/event_hash.yaml b/data/api/server-server/definitions/event_hash.yaml new file mode 100644 index 00000000..b88ac82e --- /dev/null +++ b/data/api/server-server/definitions/event_hash.yaml @@ -0,0 +1,13 @@ +type: object +title: Event Hash +description: |- + Content hashes of the PDU, following the algorithm specified in [Signing Events](/server-server-api/#signing-events). +example: { + "sha256": "ThisHashCoversAllFieldsInCaseThisIsRedacted" +} +properties: + sha256: + type: string + description: The hash. + example: ThisHashCoversAllFieldsInCaseThisIsRedacted +required: ['sha256'] diff --git a/data/api/server-server/definitions/keys.yaml b/data/api/server-server/definitions/keys.yaml index efb76f26..c3f71083 100644 --- a/data/api/server-server/definitions/keys.yaml +++ b/data/api/server-server/definitions/keys.yaml @@ -19,7 +19,7 @@ example: properties: server_name: type: string - description: DNS name of the homeserver. + description: The homeserver's [server name](/appendices/#server-name). example: "example.org" verify_keys: type: object @@ -98,4 +98,4 @@ properties: publishes a key which is valid for a significant amount of time without a way for the homeserver owner to revoke it. example: 1052262000000 -required: ["server_name", "verify_keys"] +required: ["server_name", "verify_keys", "signatures", "valid_until_ts"] diff --git a/data/api/server-server/definitions/pdu.yaml b/data/api/server-server/definitions/pdu.yaml index d87db1a3..00b83321 100644 --- a/data/api/server-server/definitions/pdu.yaml +++ b/data/api/server-server/definitions/pdu.yaml @@ -20,20 +20,12 @@ allOf: - $ref: "unsigned_pdu.yaml" - type: object properties: + redacts: + type: string + description: For redaction events, the ID of the event being redacted. + example: "$def456:matrix.org" hashes: - type: object - title: Event Hash - description: |- - Content hashes of the PDU, following the algorithm specified in [Signing Events](/server-server-api/#signing-events). - example: { - "sha256": "ThisHashCoversAllFieldsInCaseThisIsRedacted" - } - properties: - sha256: - type: string - description: The hash. - example: ThisHashCoversAllFieldsInCaseThisIsRedacted - required: ['sha256'] + $ref: "event_hash.yaml" signatures: type: object description: |- diff --git a/data/api/server-server/definitions/pdu_v11.yaml b/data/api/server-server/definitions/pdu_v11.yaml new file mode 100644 index 00000000..60f9b3ac --- /dev/null +++ b/data/api/server-server/definitions/pdu_v11.yaml @@ -0,0 +1,69 @@ +# Copyright 2019-2023 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +type: object +title: Persistent Data Unit +description: A persistent data unit (event) for room version 11 and beyond. +example: + $ref: "../examples/pdu_v11.json" +allOf: + # v11 is the v4 event, but without redacts. Copy the auth_events/prev_events + # from pdu_v4.yaml and hashes and signatures from pdu_v3.yaml. + - $ref: "unsigned_pdu_base.yaml" + - type: object + properties: + auth_events: + type: array + items: + type: string + description: Event ID. + description: |- + Event IDs for the authorization events that would + allow this event to be in the room. + + Must contain less than or equal to 10 events. Note that if the relevant + auth event selection rules are used, this restriction should never be + encountered. + example: ["$URLsafe-base64EncodedHash", "$Another_Event"] + prev_events: + type: array + items: + type: string + description: Event ID. + description: |- + Event IDs for the most recent events in the room + that the homeserver was aware of when it made this event. + + Must contain less than or equal to 20 events. + example: ["$URLsafe-base64EncodedHash", "$Another_Event"] + hashes: + $ref: "event_hash.yaml" + signatures: + type: object + description: |- + Signatures for the PDU, following the algorithm specified in [Signing Events](/server-server-api/#signing-events). + example: { + "example.com": { + "ed25519:key_version:": "86BytesOfSignatureOfTheRedactedEvent" + } + } + additionalProperties: + type: object + title: Server Signatures + additionalProperties: + type: string + required: + - auth_events + - prev_events + - hashes + - signatures diff --git a/data/api/server-server/definitions/pdu_v3.yaml b/data/api/server-server/definitions/pdu_v3.yaml index 32d05b36..e801518c 100644 --- a/data/api/server-server/definitions/pdu_v3.yaml +++ b/data/api/server-server/definitions/pdu_v3.yaml @@ -49,19 +49,7 @@ allOf: Must contain less than or equal to 20 events. example: ["$base64EncodedHash", "$AnotherEvent"] hashes: - type: object - title: Event Hash - description: |- - Content hashes of the PDU, following the algorithm specified in [Signing Events](/server-server-api/#signing-events). - example: { - "sha256": "ThisHashCoversAllFieldsInCaseThisIsRedacted" - } - properties: - sha256: - type: string - description: The hash. - example: ThisHashCoversAllFieldsInCaseThisIsRedacted - required: ['sha256'] + $ref: "event_hash.yaml" signatures: type: object description: |- diff --git a/data/api/server-server/definitions/security.yaml b/data/api/server-server/definitions/security.yaml index 822b3fdf..8b91accd 100644 --- a/data/api/server-server/definitions/security.yaml +++ b/data/api/server-server/definitions/security.yaml @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. signedRequest: - type: apiKey + type: http description: |- - The `Authorization` header defined in the [Authentication](/server-server-api/#authentication) section. - name: Authorization - in: header + The `Authorization: X-Matrix` header defined in the [Authentication](/server-server-api/#authentication) + section. + scheme: X-Matrix diff --git a/data/api/server-server/definitions/unsigned_pdu_base.yaml b/data/api/server-server/definitions/unsigned_pdu_base.yaml index c21149f6..a2ec9552 100644 --- a/data/api/server-server/definitions/unsigned_pdu_base.yaml +++ b/data/api/server-server/definitions/unsigned_pdu_base.yaml @@ -60,17 +60,7 @@ properties: - type: string title: Event ID example: "$abc123:matrix.org" - - type: object - title: Event Hash - example: { - "sha256": "Base64EncodedSha256HashesShouldBe43BytesLong" - } - properties: - sha256: - type: string - description: The event hash. - example: Base64EncodedSha256HashesShouldBe43BytesLong - required: ['sha256'] + - $ref: "event_hash.yaml" depth: type: integer description: |- @@ -96,21 +86,7 @@ properties: - type: string title: Event ID example: "$abc123:matrix.org" - - type: object - title: Event Hash - example: { - "sha256": "Base64EncodedSha256HashesShouldBe43BytesLong" - } - properties: - sha256: - type: string - description: The event hash. - example: Base64EncodedSha256HashesShouldBe43BytesLong - required: ['sha256'] - redacts: - type: string - description: For redaction events, the ID of the event being redacted. - example: "$def456:matrix.org" + - $ref: "event_hash.yaml" unsigned: type: object title: UnsignedData diff --git a/data/api/server-server/event_auth.yaml b/data/api/server-server/event_auth.yaml index 99d2b3ac..18ec0072 100644 --- a/data/api/server-server/event_auth.yaml +++ b/data/api/server-server/event_auth.yaml @@ -75,4 +75,5 @@ servers: default: /_matrix/federation/v1 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/events.yaml b/data/api/server-server/events.yaml index 009df48b..f61f6fe4 100644 --- a/data/api/server-server/events.yaml +++ b/data/api/server-server/events.yaml @@ -140,6 +140,19 @@ paths: required: - auth_chain_ids - pdu_ids + "403": + description: |- + The requesting host is not in the room, or is excluded from the room via `m.room.server_acl`. + content: + application/json: + schema: + $ref: ../client-server/definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_FORBIDDEN", + "error": "You do not have permission to access the state at the requested event." + } "404": description: |- The given `event_id` was not found or the server doesn't know about the state at @@ -203,8 +216,8 @@ paths: using the `origin_server_ts` property, whether the returned event is closer to the requested timestamp than the closest event that it could find locally. If so, it should try to backfill this event via the - [`/event/{event_id}`](#get_matrixfederationv1eventeventid) endpoint so - that it is available to for a client to query. + [`/event/{event_id}`](/server-server-api/#get_matrixfederationv1eventeventid) + endpoint so that it is available to for a client to query. operationId: getEventByTimestamp security: - accessToken: [] @@ -285,4 +298,5 @@ servers: default: /_matrix/federation/v1 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/examples/pdu_v11.json b/data/api/server-server/examples/pdu_v11.json new file mode 100644 index 00000000..292f38a0 --- /dev/null +++ b/data/api/server-server/examples/pdu_v11.json @@ -0,0 +1,19 @@ +{ + "$ref": "unsigned_pdu_base.json", + "hashes": { + "sha256": "thishashcoversallfieldsincasethisisredacted" + }, + "signatures": { + "example.com": { + "ed25519:key_version:": "these86bytesofbase64signaturecoveressentialfieldsincludinghashessocancheckredactedpdus" + } + }, + "auth_events": [ + "$urlsafe_base64_encoded_eventid", + "$a-different-event-id" + ], + "prev_events": [ + "$urlsafe_base64_encoded_eventid", + "$a-different-event-id" + ] +} diff --git a/data/api/server-server/examples/unsigned_pdu_base.json b/data/api/server-server/examples/unsigned_pdu_base.json index 4826ccef..079ee1ea 100644 --- a/data/api/server-server/examples/unsigned_pdu_base.json +++ b/data/api/server-server/examples/unsigned_pdu_base.json @@ -1,7 +1,6 @@ { "room_id": "!UcYsUzyxTGDxLBEvLy:example.org", "sender": "@alice:example.com", - "origin": "example.com", "origin_server_ts": 1404838188000, "depth": 12, "auth_events": [ diff --git a/data/api/server-server/invites-v1.yaml b/data/api/server-server/invites-v1.yaml index 270682d9..c328f05e 100644 --- a/data/api/server-server/invites-v1.yaml +++ b/data/api/server-server/invites-v1.yaml @@ -194,4 +194,5 @@ servers: default: /_matrix/federation/v1 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/invites-v2.yaml b/data/api/server-server/invites-v2.yaml index 91dfca3a..8984b6d1 100644 --- a/data/api/server-server/invites-v2.yaml +++ b/data/api/server-server/invites-v2.yaml @@ -216,4 +216,5 @@ servers: default: /_matrix/federation/v2 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/joins-v1.yaml b/data/api/server-server/joins-v1.yaml index d04e2ced..9247626a 100644 --- a/data/api/server-server/joins-v1.yaml +++ b/data/api/server-server/joins-v1.yaml @@ -155,7 +155,7 @@ paths: The request is invalid, the room the server is attempting to join has a version that is not listed in the `ver` parameters, or the server was unable to validate - [restricted room conditions](#restricted-rooms). + [restricted room conditions](/server-server-api/#restricted-rooms). The error should be passed through to clients so that they may give better feedback to users. @@ -341,7 +341,7 @@ paths: properties: origin: type: string - description: The resident server's DNS name. + description: The resident server's [server name](/appendices/#server-name). auth_chain: type: array description: |- @@ -407,4 +407,5 @@ servers: default: /_matrix/federation/v1 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/joins-v2.yaml b/data/api/server-server/joins-v2.yaml index 32819193..31f8098c 100644 --- a/data/api/server-server/joins-v2.yaml +++ b/data/api/server-server/joins-v2.yaml @@ -27,7 +27,7 @@ paths: exception of the response format being fixed. This endpoint is preferred over the v1 API as it provides - a more standarised response format. Senders which receive + a more standardised response format. Senders which receive a 400, 404, or other status code which indicates this endpoint is not available should retry using the v1 API instead. @@ -162,7 +162,7 @@ paths: properties: origin: type: string - description: The resident server's DNS name. + description: The resident server's [server name](/appendices/#server-name). members_omitted: type: boolean description: "`true` if `m.room.member` events have been omitted from `state`." @@ -207,9 +207,9 @@ paths: title: SignedMembershipEvent x-addedInMatrixVersion: "1.2" description: |- - Required if the room version [supports restricted join rules](/rooms/#feature-matrix). The signed - copy of the membership event sent to other servers by the resident server, including the resident - server's signature. + The membership event sent to other servers by the resident server including a signature + from the resident server. Required if the room is [restricted](/client-server-api/#restricted-rooms) + and the joining user is authorised by one of the conditions. servers_in_room: type: array x-addedInMatrixVersion: "1.6" @@ -307,4 +307,5 @@ servers: default: /_matrix/federation/v2 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/keys_query.yaml b/data/api/server-server/keys_query.yaml index ed9e6302..791deb0a 100644 --- a/data/api/server-server/keys_query.yaml +++ b/data/api/server-server/keys_query.yaml @@ -26,7 +26,7 @@ paths: parameters: - in: path name: serverName - description: The server's DNS name to query + description: The [server name](/appendices/#server-name) to query required: true example: matrix.org schema: diff --git a/data/api/server-server/knocks.yaml b/data/api/server-server/knocks.yaml index 266e3368..cba9d32b 100644 --- a/data/api/server-server/knocks.yaml +++ b/data/api/server-server/knocks.yaml @@ -171,8 +171,7 @@ paths: content: application/json: schema: - allOf: - - $ref: ../client-server/definitions/errors/error.yaml + $ref: ../client-server/definitions/errors/error.yaml examples: response: value: { @@ -186,8 +185,7 @@ paths: content: application/json: schema: - allOf: - - $ref: ../client-server/definitions/errors/error.yaml + $ref: ../client-server/definitions/errors/error.yaml examples: response: value: { @@ -318,8 +316,7 @@ paths: content: application/json: schema: - allOf: - - $ref: ../client-server/definitions/errors/error.yaml + $ref: ../client-server/definitions/errors/error.yaml examples: response: value: { @@ -333,8 +330,7 @@ paths: content: application/json: schema: - allOf: - - $ref: ../client-server/definitions/errors/error.yaml + $ref: ../client-server/definitions/errors/error.yaml examples: response: value: { @@ -355,4 +351,5 @@ servers: default: /_matrix/federation/v1 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/leaving-v1.yaml b/data/api/server-server/leaving-v1.yaml index ee616323..a630f6d7 100644 --- a/data/api/server-server/leaving-v1.yaml +++ b/data/api/server-server/leaving-v1.yaml @@ -263,4 +263,5 @@ servers: default: /_matrix/federation/v1 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/leaving-v2.yaml b/data/api/server-server/leaving-v2.yaml index b79ce008..0db16cbe 100644 --- a/data/api/server-server/leaving-v2.yaml +++ b/data/api/server-server/leaving-v2.yaml @@ -27,7 +27,7 @@ paths: exception of the response format being fixed. This endpoint is preferred over the v1 API as it provides - a more standarised response format. Senders which receive + a more standardised response format. Senders which receive a 400, 404, or other status code which indicates this endpoint is not available should retry using the v1 API instead. @@ -148,4 +148,5 @@ servers: default: /_matrix/federation/v2 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/public_rooms.yaml b/data/api/server-server/public_rooms.yaml index c81789ae..5bfa0f71 100644 --- a/data/api/server-server/public_rooms.yaml +++ b/data/api/server-server/public_rooms.yaml @@ -218,4 +218,5 @@ servers: default: /_matrix/federation/v1 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/query.yaml b/data/api/server-server/query.yaml index 23a6dffd..cc678208 100644 --- a/data/api/server-server/query.yaml +++ b/data/api/server-server/query.yaml @@ -45,7 +45,8 @@ paths: description: |- Performs a query to get the mapped room ID and list of resident homeservers in the room for a given room alias. Homeservers should only query room aliases - that belong to the target server (identified by the DNS Name in the alias). + that belong to the target server (identified by the [server name](/appendices/#server-name) + in the alias). Servers may wish to cache the response to this query to avoid requesting the information too often. @@ -111,17 +112,21 @@ paths: description: |- Performs a query to get profile information, such as a display name or avatar, for a given user. Homeservers should only query profiles for users that belong - to the target server (identified by the DNS Name in the user ID). + to the target server (identified by the [server name](/appendices/#server-name) + in the user ID). Servers may wish to cache the response to this query to avoid requesting the information too often. + + Servers MAY deny profile look-up over federation by responding with 403 and an + error code of `M_FORBIDDEN`. operationId: queryProfile security: - signedRequest: [] parameters: - in: query name: user_id - description: The user ID to query. + description: The user ID to query. Must be a user local to the receiving homeserver. required: true example: "@someone:example.org" schema: @@ -170,6 +175,20 @@ paths: "displayname": "John Doe", "avatar_url": "mxc://matrix.org/MyC00lAvatar" } + "403": + x-addedInMatrixVersion: "1.12" + description: The server is unwilling to disclose whether the user exists and/or + has profile information. + content: + application/json: + schema: + $ref: ../client-server/definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_FORBIDDEN", + "error": "Profile lookup over federation is disabled on this homeserver" + } "404": description: The user does not exist or does not have a profile. content: @@ -196,4 +215,5 @@ servers: default: /_matrix/federation/v1 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/space_hierarchy.yaml b/data/api/server-server/space_hierarchy.yaml index aa98158f..8394588b 100644 --- a/data/api/server-server/space_hierarchy.yaml +++ b/data/api/server-server/space_hierarchy.yaml @@ -63,6 +63,7 @@ paths: allOf: - $ref: ../client-server/definitions/public_rooms_chunk.yaml - type: object + title: SpaceHierarchyParentRoom properties: room_type: type: string @@ -74,7 +75,7 @@ paths: items: type: string description: |- - If the room is a [restricted room](#restricted-rooms), these are the room IDs which + If the room is a [restricted room](/server-server-api/#restricted-rooms), these are the room IDs which are specified by the join rules. Empty or omitted otherwise. children_state: type: array @@ -106,6 +107,7 @@ paths: allOf: - $ref: ../client-server/definitions/public_rooms_chunk.yaml - type: object + title: SpaceHierarchyChildRoomsChunk properties: room_type: type: string @@ -117,12 +119,8 @@ paths: items: type: string description: |- - If the room is a [restricted room](#restricted-rooms), these are the room IDs which + If the room is a [restricted room](/server-server-api/#restricted-rooms), these are the room IDs which are specified by the join rules. Empty or omitted otherwise. - required: - - room_type - - allowed_room_ids - - children_state inaccessible_children: type: array items: @@ -230,4 +228,5 @@ servers: default: /_matrix/federation/v1 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/third_party_invite.yaml b/data/api/server-server/third_party_invite.yaml index 3eac4811..76a7d2ff 100644 --- a/data/api/server-server/third_party_invite.yaml +++ b/data/api/server-server/third_party_invite.yaml @@ -329,4 +329,5 @@ servers: default: /_matrix/federation/v1 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/transactions.yaml b/data/api/server-server/transactions.yaml index 1ca2ed3c..48377553 100644 --- a/data/api/server-server/transactions.yaml +++ b/data/api/server-server/transactions.yaml @@ -74,17 +74,19 @@ paths: description: |- The PDUs from the original transaction. The string key represents the ID of the PDU (event) that was processed. - additionalProperties: - type: object - title: PDU Processing Result - description: Information about how the PDU was handled. - properties: - error: - type: string - description: |- - A human readable description about what went wrong in processing this PDU. - If no error is present, the PDU can be considered successfully handled. - example: You are not allowed to send a message to this room. + patternProperties: + "^\\$": + x-pattern-format: mx-event-id + type: object + title: PDU Processing Result + description: Information about how the PDU was handled. + properties: + error: + type: string + description: |- + A human readable description about what went wrong in processing this PDU. + If no error is present, the PDU can be considered successfully handled. + example: You are not allowed to send a message to this room. required: - pdus examples: @@ -111,4 +113,5 @@ servers: default: /_matrix/federation/v1 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/user_devices.yaml b/data/api/server-server/user_devices.yaml index a0022f56..8a5669c4 100644 --- a/data/api/server-server/user_devices.yaml +++ b/data/api/server-server/user_devices.yaml @@ -120,4 +120,5 @@ servers: default: /_matrix/federation/v1 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/api/server-server/user_keys.yaml b/data/api/server-server/user_keys.yaml index fb598e94..059dcae4 100644 --- a/data/api/server-server/user_keys.yaml +++ b/data/api/server-server/user_keys.yaml @@ -20,7 +20,22 @@ paths: /user/keys/claim: post: summary: Claims one-time encryption keys for a user. - description: Claims one-time keys for use in pre-key messages. + description: |- + Claims one-time keys for use in pre-key messages. + + The request contains the user ID, device ID and algorithm name of the + keys that are required. If a key matching these requirements can be + found, the response contains it. The returned key is a one-time key + if one is available, and otherwise a fallback key. + + One-time keys are given out in the order that they were uploaded via + [/keys/upload](/client-server-api/#post_matrixclientv3keysupload). (All + keys uploaded within a given call to `/keys/upload` are considered + equivalent in this regard; no ordering is specified within them.) + + Servers must ensure that each one-time key is returned at most once, + so when a key has been returned, no other request will ever return + the same key. operationId: claimUserEncryptionKeys security: - signedRequest: [] @@ -34,13 +49,16 @@ paths: type: object description: |- The keys to be claimed. A map from user ID, to a map from - device ID to algorithm name. - additionalProperties: - type: object - additionalProperties: - type: string - description: algorithm - example: signed_curve25519 + device ID to algorithm name. Requested users must be local + to the receiving homeserver. + patternProperties: + "^@": + x-pattern-format: mx-user-id + type: object + additionalProperties: + type: string + description: algorithm + example: signed_curve25519 example: "@alice:example.com": JLAFKJWSCS: signed_curve25519 @@ -64,35 +82,37 @@ paths: See the [Client-Server Key Algorithms](/client-server-api/#key-algorithms) section for more information on the Key Object format. # User - additionalProperties: - type: object - # Device - additionalProperties: + patternProperties: + "^@": + x-pattern-format: mx-user-id type: object - # Key + # Device additionalProperties: - oneOf: - - type: string - - type: object - title: KeyObject - properties: - key: - type: string - description: The key, encoded using unpadded base64. - signatures: - type: object - title: Signatures - additionalProperties: + type: object + # Key + additionalProperties: + oneOf: + - type: string + - type: object + title: KeyObject + properties: + key: + type: string + description: The key, encoded using unpadded base64. + signatures: type: object + title: Signatures additionalProperties: - type: string - description: |- - Signature of the key object. + type: object + additionalProperties: + type: string + description: |- + Signature of the key object. - The signature is calculated using the process described at [Signing JSON](/appendices/#signing-json). - required: - - key - - signatures + The signature is calculated using the process described at [Signing JSON](/appendices/#signing-json). + required: + - key + - signatures example: "@alice:example.com": JLAFKJWSCS: @@ -121,12 +141,15 @@ paths: description: |- The keys to be downloaded. A map from user ID, to a list of device IDs, or to an empty list to indicate all devices for the - corresponding user. - additionalProperties: - type: array - items: - type: string - description: Device ID + corresponding user. Requested users must be local to the + receiving homeserver. + patternProperties: + "^@": + x-pattern-format: mx-user-id + type: array + items: + type: string + description: Device ID example: "@alice:example.com": [] required: @@ -148,23 +171,25 @@ paths: the information returned will be the same as uploaded via `/keys/upload`, with the addition of an `unsigned` property. - additionalProperties: - type: object - additionalProperties: - allOf: - - $ref: ../client-server/definitions/device_keys.yaml - properties: - unsigned: - title: UnsignedDeviceInfo - type: object - description: |- - Additional data added to the device key information - by intermediate servers, and not covered by the - signatures. - properties: - device_display_name: - type: string - description: The display name which the user set on the device. + patternProperties: + "^@": + x-pattern-format: mx-user-id + type: object + additionalProperties: + allOf: + - $ref: ../client-server/definitions/device_keys.yaml + properties: + unsigned: + title: UnsignedDeviceInfo + type: object + description: |- + Additional data added to the device key information + by intermediate servers, and not covered by the + signatures. + properties: + device_display_name: + type: string + description: The display name which the user set on the device. master_keys: x-addedInMatrixVersion: "1.1" type: object @@ -175,9 +200,11 @@ paths: `/keys/device_signing/upload`, along with the signatures uploaded via `/keys/signatures/upload` that the user is allowed to see. - additionalProperties: - allOf: - - $ref: ../client-server/definitions/cross_signing_key.yaml + patternProperties: + "^@": + x-pattern-format: mx-user-id + allOf: + - $ref: ../client-server/definitions/cross_signing_key.yaml example: "@alice:example.com": user_id: "@alice:example.com" @@ -193,9 +220,11 @@ paths: from user ID, to self-signing key information. For each key, the information returned will be the same as uploaded via `/keys/device_signing/upload`. - additionalProperties: - allOf: - - $ref: ../client-server/definitions/cross_signing_key.yaml + patternProperties: + "^@": + x-pattern-format: mx-user-id + allOf: + - $ref: ../client-server/definitions/cross_signing_key.yaml example: "@alice:example.com": user_id: "@alice:example.com" @@ -250,4 +279,5 @@ servers: default: /_matrix/federation/v1 components: securitySchemes: - $ref: definitions/security.yaml + signedRequest: + $ref: definitions/security.yaml#/signedRequest diff --git a/data/event-schemas/examples/core/room_event.json b/data/event-schemas/examples/core/room_event.json index 521225cc..9bd62e28 100644 --- a/data/event-schemas/examples/core/room_event.json +++ b/data/event-schemas/examples/core/room_event.json @@ -5,6 +5,7 @@ "sender": "@example:example.org", "origin_server_ts": 1432735824653, "unsigned": { - "age": 1234 + "age": 1234, + "membership": "join" } } diff --git a/data/event-schemas/examples/m.call.answer.yaml b/data/event-schemas/examples/m.call.answer.yaml index 78b48878..8a627360 100644 --- a/data/event-schemas/examples/m.call.answer.yaml +++ b/data/event-schemas/examples/m.call.answer.yaml @@ -8,6 +8,14 @@ "answer": { "type" : "answer", "sdp" : "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]" + }, + "sdp_stream_metadata": { + "271828182845": { + "purpose": "m.screenshare" + }, + "314159265358": { + "purpose": "m.usermedia" + } } } } diff --git a/data/event-schemas/examples/m.call.invite.yaml b/data/event-schemas/examples/m.call.invite.yaml index 45600001..9547854b 100644 --- a/data/event-schemas/examples/m.call.invite.yaml +++ b/data/event-schemas/examples/m.call.invite.yaml @@ -9,6 +9,14 @@ "offer": { "type" : "offer", "sdp" : "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]" + }, + "sdp_stream_metadata": { + "271828182845": { + "purpose": "m.screenshare" + }, + "314159265358": { + "purpose": "m.usermedia" + } } } } diff --git a/data/event-schemas/examples/m.call.negotiate.yaml b/data/event-schemas/examples/m.call.negotiate.yaml index f4ad8587..aaf9daf2 100644 --- a/data/event-schemas/examples/m.call.negotiate.yaml +++ b/data/event-schemas/examples/m.call.negotiate.yaml @@ -6,9 +6,17 @@ "party_id": "67890", "call_id": "12345", "lifetime": 10000, - "offer": { + "description": { "type" : "offer", "sdp" : "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]" + }, + "sdp_stream_metadata": { + "271828182845": { + "purpose": "m.screenshare" + }, + "314159265358": { + "purpose": "m.usermedia" + } } } } diff --git a/data/event-schemas/examples/m.call.sdp_stream_metadata_changed.yaml b/data/event-schemas/examples/m.call.sdp_stream_metadata_changed.yaml new file mode 100644 index 00000000..43b4fd75 --- /dev/null +++ b/data/event-schemas/examples/m.call.sdp_stream_metadata_changed.yaml @@ -0,0 +1,16 @@ +{ + "$ref": "core/room_event.json", + "type": "m.call.sdp_stream_metadata_changed", + "content": { + "version": "1", + "call_id": "1414213562373095", + "party_id": "1732050807568877", + "sdp_stream_metadata": { + "2311546231": { + "purpose": "m.usermedia", + "audio_muted:": true, + "video_muted": true + } + } + } +} diff --git a/data/event-schemas/examples/m.marked_unread.yaml b/data/event-schemas/examples/m.marked_unread.yaml new file mode 100644 index 00000000..b9937196 --- /dev/null +++ b/data/event-schemas/examples/m.marked_unread.yaml @@ -0,0 +1,7 @@ +{ + "$ref": "core/event.json", + "type": "m.marked_unread", + "content": { + "unread": true + } +} diff --git a/data/event-schemas/examples/m.receipt.yaml b/data/event-schemas/examples/m.receipt.yaml index 17e5a67e..f09872b5 100644 --- a/data/event-schemas/examples/m.receipt.yaml +++ b/data/event-schemas/examples/m.receipt.yaml @@ -4,7 +4,7 @@ "content": { "$1435641916114394fHBLK:matrix.org": { "m.read": { - "@rikj:jki.re": { + "@erikj:jki.re": { "ts": 1436451550453 } }, diff --git a/data/event-schemas/examples/m.room.create.yaml b/data/event-schemas/examples/m.room.create.yaml index e33dbc3b..390ea78d 100644 --- a/data/event-schemas/examples/m.room.create.yaml +++ b/data/event-schemas/examples/m.room.create.yaml @@ -3,8 +3,7 @@ "type": "m.room.create", "state_key": "", "content": { - "creator": "@example:example.org", - "room_version": "1", + "room_version": "11", "m.federate": true, "predecessor": { "event_id": "$something:example.org", diff --git a/data/event-schemas/examples/m.room.redaction.yaml b/data/event-schemas/examples/m.room.redaction.yaml index 42bc8411..457b0a37 100644 --- a/data/event-schemas/examples/m.room.redaction.yaml +++ b/data/event-schemas/examples/m.room.redaction.yaml @@ -1,8 +1,8 @@ { "$ref": "core/room_event.json", "type": "m.room.redaction", - "redacts": "$fukweghifu23:localhost", "content": { + "redacts": "$fukweghifu23:localhost", "reason": "Spamming" } } diff --git a/data/event-schemas/schema/components/sdp_stream_metadata.yaml b/data/event-schemas/schema/components/sdp_stream_metadata.yaml new file mode 100644 index 00000000..35566abe --- /dev/null +++ b/data/event-schemas/schema/components/sdp_stream_metadata.yaml @@ -0,0 +1,41 @@ +type: object +x-addedInMatrixVersion: "1.10" +description: |- + Metadata describing the [streams](/client-server-api/#streams) that will be + sent. + + This is a map of stream ID to metadata about the stream. +additionalProperties: + type: object + title: StreamMetadata + description: Metadata describing a stream. + properties: + purpose: + type: string + enum: + - m.usermedia + - m.screenshare + description: |- + The purpose of the stream. + + The possible values are: + + * `m.usermedia`: Stream that contains the webcam and/or microphone + tracks. + * `m.screenshare`: Stream with the screen-sharing tracks. + audio_muted: + type: boolean + description: |- + Whether the audio track in the stream is muted. + + Defaults to `false` if not present. + x-addedInMatrixVersion: "1.11" + video_muted: + type: boolean + description: |- + Whether the video track in the stream is muted. + + Defaults to `false` if not present. + x-addedInMatrixVersion: "1.11" + required: + - purpose diff --git a/data/event-schemas/schema/core-event-schema/msgtype_infos/avatar_info.yaml b/data/event-schemas/schema/core-event-schema/msgtype_infos/avatar_info.yaml new file mode 100644 index 00000000..c21dfb48 --- /dev/null +++ b/data/event-schemas/schema/core-event-schema/msgtype_infos/avatar_info.yaml @@ -0,0 +1,28 @@ +description: Metadata about an avatar image. +properties: + h: + description: |- + The intended display height of the image in pixels. This may + differ from the intrinsic dimensions of the image file. + type: integer + w: + description: |- + The intended display width of the image in pixels. This may + differ from the intrinsic dimensions of the image file. + type: integer + mimetype: + description: The mimetype of the image, e.g. `image/jpeg`. + type: string + size: + description: Size of the image in bytes. + type: integer + thumbnail_url: + description: |- + The URL (typically [`mxc://` URI](/client-server-api/#matrix-content-mxc-uris)) to a thumbnail of the image. + type: string + thumbnail_info: + allOf: + - $ref: thumbnail_info.yaml + description: Metadata about the image referred to in `thumbnail_url`. +title: AvatarInfo +type: object diff --git a/data/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml b/data/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml index 9607d6fd..7cbfcc87 100644 --- a/data/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml +++ b/data/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml @@ -1,4 +1,3 @@ -$schema: http://json-schema.org/draft-04/schema# description: Metadata about an image. properties: h: diff --git a/data/event-schemas/schema/core-event-schema/msgtype_infos/thumbnail_info.yaml b/data/event-schemas/schema/core-event-schema/msgtype_infos/thumbnail_info.yaml index 79f7c253..31a3b1b2 100644 --- a/data/event-schemas/schema/core-event-schema/msgtype_infos/thumbnail_info.yaml +++ b/data/event-schemas/schema/core-event-schema/msgtype_infos/thumbnail_info.yaml @@ -1,4 +1,3 @@ -$schema: http://json-schema.org/draft-04/schema# description: Metadata about a thumbnail image. properties: h: diff --git a/data/event-schemas/schema/m.call.answer.yaml b/data/event-schemas/schema/m.call.answer.yaml index 163690be..f68ceea8 100644 --- a/data/event-schemas/schema/m.call.answer.yaml +++ b/data/event-schemas/schema/m.call.answer.yaml @@ -1,6 +1,7 @@ { "type": "object", "description": "This event is sent by the callee when they wish to answer the call.", + "x-weight": 40, "allOf": [{ "$ref": "core-event-schema/room_event.yaml" }], @@ -27,6 +28,9 @@ } }, "required": ["type", "sdp"] + }, + "sdp_stream_metadata": { + "$ref": "components/sdp_stream_metadata.yaml" } }, "required": ["answer"] diff --git a/data/event-schemas/schema/m.call.candidates.yaml b/data/event-schemas/schema/m.call.candidates.yaml index 6aa16229..194cbda2 100644 --- a/data/event-schemas/schema/m.call.candidates.yaml +++ b/data/event-schemas/schema/m.call.candidates.yaml @@ -1,45 +1,50 @@ -{ - "type": "object", - "description": "This event is sent by callers after sending an invite and by the callee after answering. Its purpose is to give the other party additional ICE candidates to try using to communicate.", - "allOf": [{ - "$ref": "core-event-schema/room_event.yaml" - }], - "properties": { - "content": { - "type": "object", - "allOf": [{ - "$ref": "core-event-schema/call_event.yaml" - }], - "properties": { - "candidates": { - "type": "array", - "description": "Array of objects describing the candidates.", - "items": { - "type": "object", - "title": "Candidate", - "properties": { - "sdpMid": { - "type": "string", - "description": "The SDP media type this candidate is intended for." - }, - "sdpMLineIndex": { - "type": "number", - "description": "The index of the SDP 'm' line this candidate is intended for." - }, - "candidate": { - "type": "string", - "description": "The SDP 'a' line of the candidate." - } - }, - "required": ["candidate", "sdpMLineIndex", "sdpMid"] - } - } - }, - "required": ["candidates"] - }, - "type": { - "type": "string", - "enum": ["m.call.candidates"] - } - } -} +type: object +description: |- + This event is sent by callers after sending an invite and by the callee after + answering. Its purpose is to give the other party additional ICE candidates to + try using to communicate. +x-weight: 20 +allOf: + - $ref: core-event-schema/room_event.yaml +properties: + content: + type: object + allOf: + - $ref: core-event-schema/call_event.yaml + properties: + candidates: + type: array + description: Array of objects describing the candidates. + items: + type: object + title: Candidate + properties: + sdpMid: + type: string + description: |- + The SDP media type this candidate is intended for. + + At least one of `sdpMid` or `sdpMLineIndex` is required, unless + this an end-of-candidates candidate. + sdpMLineIndex: + type: number + description: |- + The index of the SDP 'm' line this candidate is intended for. + + At least one of `sdpMid` or `sdpMLineIndex` is required, unless + this an end-of-candidates candidate. + candidate: + type: string + description: |- + The SDP 'a' line of the candidate. + + If this is an [end-of-candidates](/client-server-api/#end-of-candidates) + candidate, this is the empty string. + required: + - candidate + required: + - candidates + type: + type: string + enum: + - m.call.candidates \ No newline at end of file diff --git a/data/event-schemas/schema/m.call.hangup.yaml b/data/event-schemas/schema/m.call.hangup.yaml index 0ca7fb65..94f77636 100644 --- a/data/event-schemas/schema/m.call.hangup.yaml +++ b/data/event-schemas/schema/m.call.hangup.yaml @@ -21,6 +21,7 @@ description: | the new call unless the user had specifically chosen to do so. * `unknown_error`: Some other failure occurred that meant the client was unable to continue the call rather than the user choosing to end it. +x-weight: 80 allOf: - "$ref": core-event-schema/room_event.yaml properties: diff --git a/data/event-schemas/schema/m.call.invite.yaml b/data/event-schemas/schema/m.call.invite.yaml index 72020b26..6b7818a6 100644 --- a/data/event-schemas/schema/m.call.invite.yaml +++ b/data/event-schemas/schema/m.call.invite.yaml @@ -1,6 +1,7 @@ { "type": "object", "description": "This event is sent by the caller when they wish to establish a call.", + "x-weight": 10, "allOf": [{ "$ref": "core-event-schema/room_event.yaml" }], @@ -35,7 +36,10 @@ "invitee": { "type": "string", "description": "The ID of the user being called. If omitted, any user in the room can answer.", - "x-addedInMatrixVersion": "1.7", + "x-addedInMatrixVersion": "1.7" + }, + "sdp_stream_metadata": { + "$ref": "components/sdp_stream_metadata.yaml" } }, "required": ["offer", "lifetime"] diff --git a/data/event-schemas/schema/m.call.negotiate.yaml b/data/event-schemas/schema/m.call.negotiate.yaml index abc5ef1d..69216b44 100644 --- a/data/event-schemas/schema/m.call.negotiate.yaml +++ b/data/event-schemas/schema/m.call.negotiate.yaml @@ -34,6 +34,7 @@ description: | attempt to validate the `type` field, but simply pass the object into the WebRTC API. x-addedInMatrixVersion: "1.7" +x-weight: 60 allOf: - "$ref": core-event-schema/room_event.yaml properties: @@ -42,15 +43,16 @@ properties: allOf: - "$ref": core-event-schema/call_event.yaml properties: - offer: + description: type: object - title: Offer + title: Description description: The session description object properties: type: type: string enum: - offer + - answer description: The type of session description. sdp: type: string @@ -60,12 +62,12 @@ properties: - sdp lifetime: type: integer - description: The time in milliseconds that the invite is valid for. - Once the invite age exceeds this value, clients should discard it. - They should also no longer show the call as awaiting an answer in the - UI. + description: The time in milliseconds that the negotiation is valid for. + Once the negotiation age exceeds this value, clients should discard it. + sdp_stream_metadata: + $ref: components/sdp_stream_metadata.yaml required: - - offer + - description - lifetime type: type: string diff --git a/data/event-schemas/schema/m.call.reject.yaml b/data/event-schemas/schema/m.call.reject.yaml index 39726c1a..71379fb2 100644 --- a/data/event-schemas/schema/m.call.reject.yaml +++ b/data/event-schemas/schema/m.call.reject.yaml @@ -14,13 +14,12 @@ description: | Note that, unlike `m.call.hangup`, this event has no `reason` field: the rejection of a call is always implicitly because the user chose not to answer it. x-addedInMatrixVersion: "1.7" +x-weight: 30 allOf: - "$ref": core-event-schema/room_event.yaml properties: content: - type: object - allOf: - - "$ref": core-event-schema/call_event.yaml + "$ref": core-event-schema/call_event.yaml type: type: string enum: diff --git a/data/event-schemas/schema/m.call.sdp_stream_metadata_changed.yaml b/data/event-schemas/schema/m.call.sdp_stream_metadata_changed.yaml new file mode 100644 index 00000000..1ff2dca8 --- /dev/null +++ b/data/event-schemas/schema/m.call.sdp_stream_metadata_changed.yaml @@ -0,0 +1,22 @@ +type: object +x-addedInMatrixVersion: "1.11" +x-weight: 70 +description: |- + This event is sent by callers when they wish to update a stream's metadata + but no negotiation is required. +allOf: + - $ref: core-event-schema/room_event.yaml +properties: + content: + type: object + allOf: + - $ref: core-event-schema/call_event.yaml + properties: + sdp_stream_metadata: + $ref: components/sdp_stream_metadata.yaml + required: + - sdp_stream_metadata + type: + type: string + enum: + - m.call.sdp_stream_metadata_changed diff --git a/data/event-schemas/schema/m.call.select_answer.yaml b/data/event-schemas/schema/m.call.select_answer.yaml index b47c1352..fb16eddf 100644 --- a/data/event-schemas/schema/m.call.select_answer.yaml +++ b/data/event-schemas/schema/m.call.select_answer.yaml @@ -2,6 +2,7 @@ "type": "object", "description": "This event is sent by the caller's client once it has decided which other client to talk to, by selecting one of multiple possible incoming `m.call.answer` events. Its `selected_party_id` field indicates the answer it's chosen. The `call_id` and `party_id` of the caller is also included. If the callee's client sees a `select_answer` for an answer with party ID other than the one it sent, it ends the call and informs the user the call was answered elsewhere. It does not send any events. Media can start flowing before this event is seen or even sent. Clients that implement previous versions of this specification will ignore this event and behave as they did before.", "x-addedInMatrixVersion": "1.7", + "x-weight": 50, "allOf": [{ "$ref": "core-event-schema/room_event.yaml" }], diff --git a/data/event-schemas/schema/m.direct.yaml b/data/event-schemas/schema/m.direct.yaml index f00b83bc..9b9e8251 100644 --- a/data/event-schemas/schema/m.direct.yaml +++ b/data/event-schemas/schema/m.direct.yaml @@ -9,12 +9,16 @@ description: |- that user ID. properties: content: - additionalProperties: - type: array - title: User ID - items: - type: string + patternProperties: + "^@": + x-pattern-format: mx-user-id + type: array + items: + type: string type: object + description: |- + The mapping of user ID to a list of room IDs of the 'direct' rooms for + that user ID. type: enum: - m.direct diff --git a/data/event-schemas/schema/m.forwarded_room_key.yaml b/data/event-schemas/schema/m.forwarded_room_key.yaml index 10b8b652..101716a0 100644 --- a/data/event-schemas/schema/m.forwarded_room_key.yaml +++ b/data/event-schemas/schema/m.forwarded_room_key.yaml @@ -4,7 +4,7 @@ allOf: description: |- This event type is used to forward keys for end-to-end encryption. - It is encrypted as an `m.room.encrypted` event using [Olm](#molmv1curve25519-aes-sha2), + It is encrypted as an `m.room.encrypted` event using [Olm](/client-server-api/#molmv1curve25519-aes-sha2), then sent as a [to-device](/client-server-api/#send-to-device-messaging) event. properties: content: diff --git a/data/event-schemas/schema/m.ignored_user_list.yaml b/data/event-schemas/schema/m.ignored_user_list.yaml index 0f0b2f85..af838490 100644 --- a/data/event-schemas/schema/m.ignored_user_list.yaml +++ b/data/event-schemas/schema/m.ignored_user_list.yaml @@ -10,14 +10,14 @@ properties: properties: ignored_users: type: object - title: "Ignored users" - description: "The map of users to ignore" + description: |- + The map of users to ignore. This is a mapping of user ID to empty + object. patternProperties: "^@": type: "object" - title: "Ignored User" description: "An empty object for future enhancement" - x-pattern: "$USER_ID" + x-pattern-format: "mx-user-id" required: - ignored_users type: diff --git a/data/event-schemas/schema/m.key.verification.accept.yaml b/data/event-schemas/schema/m.key.verification.accept.yaml index 2a1bbf0d..a61edd66 100644 --- a/data/event-schemas/schema/m.key.verification.accept.yaml +++ b/data/event-schemas/schema/m.key.verification.accept.yaml @@ -44,8 +44,7 @@ properties: ephemeral public key (encoded as unpadded base64) and the canonical JSON representation of the `m.key.verification.start` message. m.relates_to: - allOf: - - $ref: m.key.verification.m.relates_to.yaml + $ref: m.key.verification.m.relates_to.yaml required: - method - key_agreement_protocol diff --git a/data/event-schemas/schema/m.key.verification.cancel.yaml b/data/event-schemas/schema/m.key.verification.cancel.yaml index 6474b763..237f0d06 100644 --- a/data/event-schemas/schema/m.key.verification.cancel.yaml +++ b/data/event-schemas/schema/m.key.verification.cancel.yaml @@ -58,8 +58,7 @@ properties: respond again with `m.unexpected_message` to avoid the other device potentially sending another error response. m.relates_to: - allOf: - - $ref: m.key.verification.m.relates_to.yaml + $ref: m.key.verification.m.relates_to.yaml required: - code - reason diff --git a/data/event-schemas/schema/m.key.verification.done.yaml b/data/event-schemas/schema/m.key.verification.done.yaml index bfdc540b..0e1c24e6 100644 --- a/data/event-schemas/schema/m.key.verification.done.yaml +++ b/data/event-schemas/schema/m.key.verification.done.yaml @@ -13,8 +13,7 @@ properties: Required when sent as a to-device message. The opaque identifier for the verification process/request. m.relates_to: - allOf: - - $ref: m.key.verification.m.relates_to.yaml + $ref: m.key.verification.m.relates_to.yaml type: object type: enum: diff --git a/data/event-schemas/schema/m.key.verification.key.yaml b/data/event-schemas/schema/m.key.verification.key.yaml index 62704ea7..c0b31c1b 100644 --- a/data/event-schemas/schema/m.key.verification.key.yaml +++ b/data/event-schemas/schema/m.key.verification.key.yaml @@ -18,8 +18,7 @@ properties: description: |- The device's ephemeral public key, encoded as unpadded base64. m.relates_to: - allOf: - - $ref: m.key.verification.m.relates_to.yaml + $ref: m.key.verification.m.relates_to.yaml required: - key type: object diff --git a/data/event-schemas/schema/m.key.verification.mac.yaml b/data/event-schemas/schema/m.key.verification.mac.yaml index 7f404fa0..ad4a3f05 100644 --- a/data/event-schemas/schema/m.key.verification.mac.yaml +++ b/data/event-schemas/schema/m.key.verification.mac.yaml @@ -29,8 +29,7 @@ properties: The MAC of the comma-separated, sorted, list of key IDs given in the `mac` property, encoded as unpadded base64. m.relates_to: - allOf: - - $ref: m.key.verification.m.relates_to.yaml + $ref: m.key.verification.m.relates_to.yaml required: - mac - keys diff --git a/data/event-schemas/schema/m.key.verification.ready.yaml b/data/event-schemas/schema/m.key.verification.ready.yaml index bf9d975b..1c5ed7bd 100644 --- a/data/event-schemas/schema/m.key.verification.ready.yaml +++ b/data/event-schemas/schema/m.key.verification.ready.yaml @@ -27,8 +27,7 @@ properties: items: type: string m.relates_to: - allOf: - - $ref: m.key.verification.m.relates_to.yaml + $ref: m.key.verification.m.relates_to.yaml required: - from_device - methods diff --git a/data/event-schemas/schema/m.key.verification.request.yaml b/data/event-schemas/schema/m.key.verification.request.yaml index 76ba618d..880d4900 100644 --- a/data/event-schemas/schema/m.key.verification.request.yaml +++ b/data/event-schemas/schema/m.key.verification.request.yaml @@ -5,7 +5,8 @@ allOf: description: |- Requests a key verification using to-device messaging. When requesting a key verification in a room, a `m.room.message` should be used, with - [`m.key.verification.request`](#mroommessagemkeyverificationrequest) as msgtype. + [`m.key.verification.request`](/client-server-api/#mroommessagemkeyverificationrequest) + as msgtype. properties: content: properties: diff --git a/data/event-schemas/schema/m.key.verification.start$m.reciprocate.v1.yaml b/data/event-schemas/schema/m.key.verification.start$m.reciprocate.v1.yaml index a60711b3..4f3071ac 100644 --- a/data/event-schemas/schema/m.key.verification.start$m.reciprocate.v1.yaml +++ b/data/event-schemas/schema/m.key.verification.start$m.reciprocate.v1.yaml @@ -30,8 +30,7 @@ properties: description: |- The shared secret from the QR code, encoded using unpadded base64. m.relates_to: - allOf: - - $ref: m.key.verification.m.relates_to.yaml + $ref: m.key.verification.m.relates_to.yaml required: - from_device - method diff --git a/data/event-schemas/schema/m.key.verification.start$m.sas.v1.yaml b/data/event-schemas/schema/m.key.verification.start$m.sas.v1.yaml index 9bc7bcad..c5f2e8af 100644 --- a/data/event-schemas/schema/m.key.verification.start$m.sas.v1.yaml +++ b/data/event-schemas/schema/m.key.verification.start$m.sas.v1.yaml @@ -58,8 +58,7 @@ properties: type: string enum: ["decimal", "emoji"] m.relates_to: - allOf: - - $ref: m.key.verification.m.relates_to.yaml + $ref: m.key.verification.m.relates_to.yaml required: - from_device - method diff --git a/data/event-schemas/schema/m.key.verification.start.yaml b/data/event-schemas/schema/m.key.verification.start.yaml index a36a72f8..cc16d275 100644 --- a/data/event-schemas/schema/m.key.verification.start.yaml +++ b/data/event-schemas/schema/m.key.verification.start.yaml @@ -32,8 +32,7 @@ properties: when the `method` chosen only verifies one user's key. This field will never be present if the `method` verifies keys both ways. m.relates_to: - allOf: - - $ref: m.key.verification.m.relates_to.yaml + $ref: m.key.verification.m.relates_to.yaml required: - from_device - method diff --git a/data/event-schemas/schema/m.marked_unread.yaml b/data/event-schemas/schema/m.marked_unread.yaml new file mode 100644 index 00000000..56b3ba62 --- /dev/null +++ b/data/event-schemas/schema/m.marked_unread.yaml @@ -0,0 +1,25 @@ +{ + "type": "object", + "title": "Unread Marker Event", + "description": "The current state of the user's unread marker in a room. This event appears in the user's room account data for the room the marker is applicable for.", + "allOf": [{ + "$ref": "core-event-schema/event.yaml" + }], + "properties": { + "content": { + "type": "object", + "properties": { + "unread": { + "type": "boolean", + "description": "Whether the room is marked unread or not." + } + }, + "required": ["unread"] + }, + "type": { + "type": "string", + "enum": ["m.marked_unread"] + } + }, + "required": ["type", "content"] +} diff --git a/data/event-schemas/schema/m.receipt.yaml b/data/event-schemas/schema/m.receipt.yaml index 6062d31f..23a5d835 100644 --- a/data/event-schemas/schema/m.receipt.yaml +++ b/data/event-schemas/schema/m.receipt.yaml @@ -9,22 +9,24 @@ allOf: properties: content: type: object + description: |- + The mapping of event ID to a collection of receipts for this + event ID. The event ID is the ID of the event being acknowledged + and *not* an ID for the receipt itself. patternProperties: "^\\$": type: object - x-pattern: "$EVENT_ID" - title: Receipts + x-pattern-format: "mx-event-id" + title: Event Receipts description: |- - The mapping of event ID to a collection of receipts for this - event ID. The event ID is the ID of the event being acknowledged - and *not* an ID for the receipt itself. + The collection of receipts for this event ID. properties: "m.read": type: object - title: Users description: |- A collection of users who have sent `m.read` receipts for - this event. + this event. The string key is the user ID the receipt + belongs to. patternProperties: "^@": &receiptUserMap type: object @@ -32,7 +34,7 @@ properties: description: |- The mapping of user ID to receipt. The user ID is the entity who sent this receipt. - x-pattern: "$USER_ID" + x-pattern-format: "mx-user-id" properties: ts: type: integer @@ -48,7 +50,6 @@ properties: (default). "m.read.private": type: object - title: Own User description: |- Similar to `m.read`, the users who have sent `m.read.private` receipts for this event. Due to the nature of private read diff --git a/data/event-schemas/schema/m.room.avatar.yaml b/data/event-schemas/schema/m.room.avatar.yaml index a4777af4..5c6c7140 100644 --- a/data/event-schemas/schema/m.room.avatar.yaml +++ b/data/event-schemas/schema/m.room.avatar.yaml @@ -7,7 +7,7 @@ properties: properties: info: allOf: - - $ref: core-event-schema/msgtype_infos/image_info.yaml + - $ref: core-event-schema/msgtype_infos/avatar_info.yaml description: Metadata about the image referred to in `url`. url: description: |- diff --git a/data/event-schemas/schema/m.room.create.yaml b/data/event-schemas/schema/m.room.create.yaml index 44c9c84e..19b2bae4 100644 --- a/data/event-schemas/schema/m.room.create.yaml +++ b/data/event-schemas/schema/m.room.create.yaml @@ -6,7 +6,9 @@ properties: content: properties: creator: - description: The `user_id` of the room creator. This is set by the homeserver. + description: |- + The `user_id` of the room creator. **Required** for, and only present in, room versions 1 - 10. Starting with + room version 11 the event `sender` should be used instead. type: string m.federate: description: Whether users on other servers can join this room. Defaults to `true` if key does not exist. @@ -16,7 +18,8 @@ properties: type: string type: description: |- - Optional [room type](#types) to denote a room's intended function outside of traditional conversation. + Optional [room type](/client-server-api/#types) to denote a room's intended function outside of traditional + conversation. Unspecified room types are possible using [Namespaced Identifiers](/appendices/#common-namespaced-identifier-grammar). type: string @@ -32,8 +35,6 @@ properties: type: string description: The event ID of the last known event in the old room. required: [room_id, event_id] - required: - - creator type: object state_key: description: A zero-length string. diff --git a/data/event-schemas/schema/m.room.encrypted.yaml b/data/event-schemas/schema/m.room.encrypted.yaml index 95e05ff7..6a5689ac 100644 --- a/data/event-schemas/schema/m.room.encrypted.yaml +++ b/data/event-schemas/schema/m.room.encrypted.yaml @@ -41,34 +41,37 @@ properties: Olm event. For more details, see [Messaging Algorithms](/client-server-api/#messaging-algorithms). sender_key: type: string + deprecated: true x-changedInMatrixVersion: "1.3": |- Previously this field was required, however given it offers no additional security or privacy benefit it has been deprecated for Megolm messages. - See [`m.megolm.v1.aes-sha2`](#mmegolmv1aes-sha2) for more information. + See [`m.megolm.v1.aes-sha2`](/client-server-api/#mmegolmv1aes-sha2) for + more information. description: |- The Curve25519 key of the sender. Required (not deprecated) if not using Megolm. **Deprecated**: This field provides no additional security or privacy benefit for Megolm messages and must not be read from if the encrypted event is using Megolm. It should still be included on outgoing messages, however must not be - used to find the corresponding session. See [`m.megolm.v1.aes-sha2`](#mmegolmv1aes-sha2) + used to find the corresponding session. See [`m.megolm.v1.aes-sha2`](/client-server-api/#mmegolmv1aes-sha2) for more information. device_id: type: string + deprecated: true x-changedInMatrixVersion: "1.3": |- Previously this field was required for Megolm messages, however given it offers no additional security or privacy benefit it has been deprecated - for Megolm messages. See [`m.megolm.v1.aes-sha2`](#mmegolmv1aes-sha2) for - more information. + for Megolm messages. See [`m.megolm.v1.aes-sha2`](/client-server-api/#mmegolmv1aes-sha2) + for more information. description: |- The ID of the sending device. **Deprecated**: This field provides no additional security or privacy benefit for Megolm messages and must not be read from if the encrypted event is using Megolm. It should still be included on outgoing messages, however must not be - used to find the corresponding session. See [`m.megolm.v1.aes-sha2`](#mmegolmv1aes-sha2) + used to find the corresponding session. See [`m.megolm.v1.aes-sha2`](/client-server-api/#mmegolmv1aes-sha2) for more information. session_id: type: string diff --git a/data/event-schemas/schema/m.room.member.yaml b/data/event-schemas/schema/m.room.member.yaml index f2d297b5..8d212687 100644 --- a/data/event-schemas/schema/m.room.member.yaml +++ b/data/event-schemas/schema/m.room.member.yaml @@ -64,7 +64,7 @@ properties: type: string description: |- Usually found on `join` events, this field is used to denote which homeserver (through representation of a user with sufficient power level) - authorised the user's join. More information about this field can be found in the [Restricted Rooms Specification](#restricted-rooms). + authorised the user's join. More information about this field can be found in the [Restricted Rooms Specification](/client-server-api/#restricted-rooms). Client and server implementations should be aware of the [signing implications](/rooms/v8/#authorization-rules) of including this field in further events: in particular, the event must be signed by the server which diff --git a/data/event-schemas/schema/m.room.message$m.audio.yaml b/data/event-schemas/schema/m.room.message$m.audio.yaml index 6cf742e4..825419bd 100644 --- a/data/event-schemas/schema/m.room.message$m.audio.yaml +++ b/data/event-schemas/schema/m.room.message$m.audio.yaml @@ -6,8 +6,29 @@ properties: content: properties: body: - description: "A description of the audio e.g. 'Bee Gees - Stayin' Alive', or some kind of content description for accessibility e.g. 'audio attachment'." + description: |- + If `filename` is not set or the value of both properties are + identical, this is the filename of the original upload. Otherwise, + this is a caption for the audio. type: string + x-changedInMatrixVersion: + "1.10": This property can act as a caption for the audio. + format: + description: |- + The format used in the `formatted_body`. Currently only + `org.matrix.custom.html` is supported. + type: string + x-addedInMatrixVersion: "1.10" + formatted_body: + description: |- + The formatted version of the `body`, when it acts as a caption. This + is required if `format` is specified. + type: string + x-addedInMatrixVersion: "1.10" + filename: + description: The original filename of the uploaded file. + type: string + x-addedInMatrixVersion: "1.10" info: description: Metadata for the audio clip referred to in `url`. properties: diff --git a/data/event-schemas/schema/m.room.message$m.file.yaml b/data/event-schemas/schema/m.room.message$m.file.yaml index af181964..8e269366 100644 --- a/data/event-schemas/schema/m.room.message$m.file.yaml +++ b/data/event-schemas/schema/m.room.message$m.file.yaml @@ -6,8 +6,25 @@ properties: content: properties: body: - description: A human-readable description of the file. This is recommended to be the filename of the original upload. + description: |- + If `filename` is not set or the value of both properties are + identical, this is the filename of the original upload. Otherwise, + this is a caption for the file. type: string + x-changedInMatrixVersion: + "1.10": This property can act as a caption for the file. + format: + description: |- + The format used in the `formatted_body`. Currently only + `org.matrix.custom.html` is supported. + type: string + x-addedInMatrixVersion: "1.10" + formatted_body: + description: |- + The formatted version of the `body`, when it acts as a caption. This + is required if `format` is specified. + type: string + x-addedInMatrixVersion: "1.10" filename: description: The original filename of the uploaded file. type: string diff --git a/data/event-schemas/schema/m.room.message$m.image.yaml b/data/event-schemas/schema/m.room.message$m.image.yaml index 91985ed0..15bdeda4 100644 --- a/data/event-schemas/schema/m.room.message$m.image.yaml +++ b/data/event-schemas/schema/m.room.message$m.image.yaml @@ -6,8 +6,29 @@ properties: content: properties: body: - description: "A textual representation of the image. This could be the alt text of the image, the filename of the image, or some kind of content description for accessibility e.g. 'image attachment'." + description: |- + If `filename` is not set or the value of both properties are + identical, this is the filename of the original upload. Otherwise, + this is a caption for the image. type: string + x-changedInMatrixVersion: + "1.10": This property can act as a caption for the image. + format: + description: |- + The format used in the `formatted_body`. Currently only + `org.matrix.custom.html` is supported. + type: string + x-addedInMatrixVersion: "1.10" + formatted_body: + description: |- + The formatted version of the `body`, when it acts as a caption. This + is required if `format` is specified. + type: string + x-addedInMatrixVersion: "1.10" + filename: + description: The original filename of the uploaded file. + type: string + x-addedInMatrixVersion: "1.10" info: allOf: - $ref: core-event-schema/msgtype_infos/image_info.yaml diff --git a/data/event-schemas/schema/m.room.message$m.key.verification.request.yaml b/data/event-schemas/schema/m.room.message$m.key.verification.request.yaml index c0a0764c..43882ab9 100644 --- a/data/event-schemas/schema/m.room.message$m.key.verification.request.yaml +++ b/data/event-schemas/schema/m.room.message$m.key.verification.request.yaml @@ -3,7 +3,7 @@ allOf: - $ref: core-event-schema/room_event.yaml description: Requests a key verification in a room. When requesting a key verification - using to-device messaging, an event with type [`m.key.verification.request`](#mkeyverificationrequest) + using to-device messaging, an event with type [`m.key.verification.request`](/client-server-api/#mkeyverificationrequest) should be used. properties: content: diff --git a/data/event-schemas/schema/m.room.message$m.video.yaml b/data/event-schemas/schema/m.room.message$m.video.yaml index e3b782b8..75752534 100644 --- a/data/event-schemas/schema/m.room.message$m.video.yaml +++ b/data/event-schemas/schema/m.room.message$m.video.yaml @@ -6,8 +6,29 @@ properties: content: properties: body: - description: "A description of the video e.g. 'Gangnam style', or some kind of content description for accessibility e.g. 'video attachment'." + description: |- + If `filename` is not set or the value of both properties are + identical, this is the filename of the original upload. Otherwise, + this is a caption for the video. type: string + x-changedInMatrixVersion: + "1.10": This property can act as a caption for the video. + format: + description: |- + The format used in the `formatted_body`. Currently only + `org.matrix.custom.html` is supported. + type: string + x-addedInMatrixVersion: "1.10" + formatted_body: + description: |- + The formatted version of the `body`, when it acts as a caption. This + is required if `format` is specified. + type: string + x-addedInMatrixVersion: "1.10" + filename: + description: The original filename of the uploaded file. + type: string + x-addedInMatrixVersion: "1.10" info: description: Metadata about the video clip referred to in `url`. properties: diff --git a/data/event-schemas/schema/m.room.name.yaml b/data/event-schemas/schema/m.room.name.yaml index c9236de0..0b3b34dc 100644 --- a/data/event-schemas/schema/m.room.name.yaml +++ b/data/event-schemas/schema/m.room.name.yaml @@ -7,9 +7,8 @@ description: |- is a human-friendly string designed to be displayed to the end-user. The room name is not unique, as multiple rooms can have the same room name set. - A room with an `m.room.name` event with an absent, null, or empty - `name` field should be treated the same as a room with no `m.room.name` - event. + If a room has an `m.room.name` event with an absent, null, or empty `name` + field, it should be treated the same as a room with no `m.room.name` event. An event of this type is automatically created when creating a room using `/createRoom` with the `name` key. diff --git a/data/event-schemas/schema/m.room.power_levels.yaml b/data/event-schemas/schema/m.room.power_levels.yaml index f5f15fab..858c5274 100644 --- a/data/event-schemas/schema/m.room.power_levels.yaml +++ b/data/event-schemas/schema/m.room.power_levels.yaml @@ -67,8 +67,10 @@ properties: by the `events` key. Defaults to 50 if unspecified. type: integer users: - additionalProperties: - type: integer + patternProperties: + "^@": + x-pattern-format: mx-user-id + type: integer description: The power levels for specific users. This is a mapping from `user_id` to power level for that user. title: User power levels type: object diff --git a/data/event-schemas/schema/m.room.redaction.yaml b/data/event-schemas/schema/m.room.redaction.yaml index 143e7eff..8a7edeba 100644 --- a/data/event-schemas/schema/m.room.redaction.yaml +++ b/data/event-schemas/schema/m.room.redaction.yaml @@ -5,18 +5,19 @@ description: 'This event is created by the server to describe which event has be properties: content: properties: + redacts: + description: The event ID that was redacted. Required for, and present starting in, room version 11. + type: string reason: description: 'The reason for the redaction, if any.' type: string type: object redacts: - description: The event ID that was redacted. + description: Required for, and only present in, room versions 1 - 10. The event ID that was redacted. type: string type: enum: - m.room.redaction type: string -required: - - redacts title: Redaction type: object diff --git a/data/event-schemas/schema/m.room.third_party_invite.yaml b/data/event-schemas/schema/m.room.third_party_invite.yaml index 7a00616b..bb4883f5 100644 --- a/data/event-schemas/schema/m.room.third_party_invite.yaml +++ b/data/event-schemas/schema/m.room.third_party_invite.yaml @@ -1,5 +1,4 @@ --- -$schema: http://json-schema.org/draft-04/schema# allOf: - $ref: core-event-schema/state_event.yaml description: "Acts as an `m.room.member` invite event, where there isn't a target user_id to invite. This event contains a token and a public key whose private key must be used to sign the token. Any user who can present that signature may use this invitation to join the target room." diff --git a/data/event-schemas/schema/m.room_key.yaml b/data/event-schemas/schema/m.room_key.yaml index 34ceb9ae..c90b41b4 100644 --- a/data/event-schemas/schema/m.room_key.yaml +++ b/data/event-schemas/schema/m.room_key.yaml @@ -4,7 +4,7 @@ allOf: description: |- This event type is used to exchange keys for end-to-end encryption. - It is encrypted as an `m.room.encrypted` event using [Olm](#molmv1curve25519-aes-sha2), + It is encrypted as an `m.room.encrypted` event using [Olm](/client-server-api/#molmv1curve25519-aes-sha2), then sent as a [to-device](/client-server-api/#send-to-device-messaging) event. properties: content: diff --git a/data/event-schemas/schema/m.room_key_request.yaml b/data/event-schemas/schema/m.room_key_request.yaml index 9894456e..62b07a23 100644 --- a/data/event-schemas/schema/m.room_key_request.yaml +++ b/data/event-schemas/schema/m.room_key_request.yaml @@ -26,7 +26,7 @@ properties: x-changedInMatrixVersion: "1.3": |- Previously this field was required, however given it offers no additional - security or privacy benefit it has been deprecated. See [`m.megolm.v1.aes-sha2`](#mmegolmv1aes-sha2) + security or privacy benefit it has been deprecated. See [`m.megolm.v1.aes-sha2`](/client-server-api/#mmegolmv1aes-sha2) for more information. description: |- The Curve25519 key of the device which initiated the session originally. @@ -34,7 +34,7 @@ properties: **Deprecated**: This field provides no additional security or privacy benefit and must not be read from. It should still be included on outgoing messages (if the event for which keys are being requested for *also* has a `sender_key`), - however must not be used to find the corresponding session. See [`m.megolm.v1.aes-sha2`](#mmegolmv1aes-sha2) + however must not be used to find the corresponding session. See [`m.megolm.v1.aes-sha2`](/client-server-api/#mmegolmv1aes-sha2) for more information. session_id: type: string diff --git a/data/event-schemas/schema/m.secret.send.yaml b/data/event-schemas/schema/m.secret.send.yaml index ecf22183..a2cafb6d 100644 --- a/data/event-schemas/schema/m.secret.send.yaml +++ b/data/event-schemas/schema/m.secret.send.yaml @@ -4,7 +4,8 @@ allOf: description: |- Sent by a client to share a secret with another device, in response to an `m.secret.request` event. It must be encrypted as an `m.room.encrypted` event - using [Olm](#molmv1curve25519-aes-sha2), then sent as a to-device event. + using [Olm](/client-server-api/#molmv1curve25519-aes-sha2), then sent as a + to-device event. The `request_id` must match the ID previously given in an `m.secret.request` event. The recipient must ensure that this event comes from a device that the diff --git a/data/event-schemas/schema/m.space.child.yaml b/data/event-schemas/schema/m.space.child.yaml index feef0adc..2222b3a1 100644 --- a/data/event-schemas/schema/m.space.child.yaml +++ b/data/event-schemas/schema/m.space.child.yaml @@ -1,7 +1,7 @@ --- allOf: - $ref: core-event-schema/state_event.yaml -description: Defines the relationship of a child room to a space-room. Has no effect in rooms which are not [spaces](#spaces). +description: Defines the relationship of a child room to a space-room. Has no effect in rooms which are not [spaces](/client-server-api/#spaces). properties: content: properties: @@ -34,6 +34,8 @@ properties: Optional (default `false`) flag to denote whether the child is "suggested" or of interest to members of the space. This is primarily intended as a rendering hint for clients to display the room differently, such as eagerly rendering them in the room list. + required: + - via type: object state_key: description: The child room ID being described. diff --git a/data/event-schemas/schema/m.space.parent.yaml b/data/event-schemas/schema/m.space.parent.yaml index ced24d70..fb633789 100644 --- a/data/event-schemas/schema/m.space.parent.yaml +++ b/data/event-schemas/schema/m.space.parent.yaml @@ -20,6 +20,8 @@ properties: When multiple `canonical` parents are found, the lowest parent when ordering by room ID lexicographically by Unicode code-points should be used. + required: + - via type: object state_key: description: The parent room ID. diff --git a/data/event-schemas/schema/m.tag.yaml b/data/event-schemas/schema/m.tag.yaml index afa22420..77010350 100644 --- a/data/event-schemas/schema/m.tag.yaml +++ b/data/event-schemas/schema/m.tag.yaml @@ -17,16 +17,7 @@ "type": "object", "description": "The tags on the room and their contents.", "additionalProperties": { - "title": "Tag", - "type": "object", - "properties": { - "order": { - "type": "number", - "format": "float", - "description": - "A number in a range `[0,1]` describing a relative position of the room under the given tag." - } - } + "$ref": "../../api/client-server/definitions/tag.yaml" } } } diff --git a/data/string-formats.yaml b/data/string-formats.yaml new file mode 100644 index 00000000..352d21fc --- /dev/null +++ b/data/string-formats.yaml @@ -0,0 +1,70 @@ +# Copyright 2024 Commaille Kévin +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file contains the list of string formats supported for the `format` key +# and the `x-pattern-format` extension within JSON Schema objects in the +# OpenAPI documents within the Matrix Specification. See +# `openapi_extensions.md` [1] for more details. +# +# [1]: https://github.com/matrix-org/matrix-spec/blob/main/openapi_extensions.md#custom-x-pattern-format-key-and-custom-formats +# +# Custom formats defined in the Matrix specification should always use the `mx-` +# prefix. They should link to the section containing the definition of the +# format in the spec. +# +# Formats that are already supported in the JSON Schema specification should +# link to the RFC where they are defined, and should not use a regex to allow +# tools that recognize the format to validate it properly. +# See . +# +# All entries have the form: +# +# key: +# title: The title rendered in the specification +# url: /url/to#definition +# # regex: A regex that can be used to validate the custom format if possible. +# It should be used as the `pattern` of the string. + +mx-user-id: + title: User ID + url: appendices#user-identifiers + # regex: "^@" + +mx-event-id: + title: Event ID + url: appendices#event-ids + # regex: "^\\$" + +mx-room-id: + title: Room ID + url: appendices#room-ids + # regex: "^!" + +mx-server-name: + title: Server Name + url: appendices#server-name + # no regex + +mx-mxc-uri: + title: Matrix Content URI + url: client-server-api#matrix-content-mxc-uris + # regex: "^mxc:\\/\\/" + +uri: + title: URI + url: https://datatracker.ietf.org/doc/html/rfc3986 + +email: + title: Email Address + url: https://datatracker.ietf.org/doc/html/rfc5321#section-4.1.2 diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..52d0f21c --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/matrix-org/matrix-spec + +go 1.12 + +require github.com/matrix-org/docsy v0.0.0-20241106102557-ec7b98ee4014 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..04125160 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/FortAwesome/Font-Awesome v0.0.0-20240716171331-37eff7fa00de/go.mod h1:IUgezN/MFpCDIlFezw3L8j83oeiIuYoj28Miwr/KUYo= +github.com/matrix-org/docsy v0.0.0-20241106102557-ec7b98ee4014 h1:CNvxuuURuxkEjA0QN+lRKELc7PRDsX270e8v4GDF3II= +github.com/matrix-org/docsy v0.0.0-20241106102557-ec7b98ee4014/go.mod h1:4Ek1bcdbfU/j8hIatEjNhIs1Yua85FtQf3kLvoYZ0bQ= +github.com/twbs/bootstrap v5.3.3+incompatible/go.mod h1:fZTSrkpSf0/HkL0IIJzvVspTt1r9zuf7XlZau8kpcY0= diff --git a/layouts/404.html b/layouts/404.html index 212e20ba..c8a3523b 100644 --- a/layouts/404.html +++ b/layouts/404.html @@ -2,7 +2,7 @@

Not found

-

This page doesn't exist. Try going back to the main page for the Matrix Specification.

+

This page doesn't exist. Try going back to the main page for the Matrix Specification.

{{ end }} diff --git a/layouts/_default/_markup/render-heading.html b/layouts/_default/_markup/render-heading.html new file mode 100644 index 00000000..7ae7aba7 --- /dev/null +++ b/layouts/_default/_markup/render-heading.html @@ -0,0 +1,11 @@ +{{- /* + + This is a heading render hook (https://gohugo.io/render-hooks/headings/) + using Docsy's heading self-links hook (https://www.docsy.dev/docs/adding-content/navigation/#heading-self-links). + + This is used when a heading is encountered in markdown content to generate + the HTML for that heading. A self-link anchor is added at the end of the + heading. + +*/ -}} +{{ template "_default/_markup/td-render-heading.html" . }} diff --git a/layouts/_default/_markup/td-heading-self-link.html b/layouts/_default/_markup/td-heading-self-link.html new file mode 100644 index 00000000..3d8d7df5 --- /dev/null +++ b/layouts/_default/_markup/td-heading-self-link.html @@ -0,0 +1,11 @@ +{{- /* + + A simplified copy of the inlined "_default/_markup/_td-heading-self-link.html" + template in Docsy's "_default/_markup/td-render-heading.html" template to be + able to reuse it when the heading has custom markup. + + Takes a string which is the ID of the heading. + +*/ -}} + + \ No newline at end of file diff --git a/layouts/docs/baseof.html b/layouts/docs/baseof.html index 3e058fd0..a167f72b 100644 --- a/layouts/docs/baseof.html +++ b/layouts/docs/baseof.html @@ -6,23 +6,26 @@ */}} - + {{ partial "head.html" . }} - +
{{ partial "navbar.html" . }}
-
+
-
+ +
{{ partial "version-banner.html" . }} - {{ partial "breadcrumb.html" . }} + {{ if not .Site.Params.ui.breadcrumb_disable }}{{ partial "breadcrumb.html" . }}{{ end }} {{ block "main" . }}{{ end }}
diff --git a/layouts/docs/changelog.checklist.md b/layouts/docs/changelog.checklist.md new file mode 100644 index 00000000..17051c71 --- /dev/null +++ b/layouts/docs/changelog.checklist.md @@ -0,0 +1,34 @@ +{{- /* + + Template to render a page with a `changelog` layout as a markdown checklist. + + This transforms the markdown source of the changelog to change list items, + which in turn are them transformed into a rendered checklist. + + Stable releases will additionally have a table at the top of the page with + information about the release, including: + + * A link to the matrix-spec repository at the time of the release, with the + version taken from the `linkTitle` in the frontmatter of the page. + * The date of the release, taken from the `date` in the frontmatter of the + page. + +*/ -}} + +{{ $version := lower .LinkTitle -}} +# Matrix Specification {{ .Title }} + +{{ if ne $version "unstable" -}} +{{- /* + + Most markdown parsers require the header to recognize a markdown table, + so add an empty header. + +*/ -}} +| | | +|---|---| +| Git commit | {{ printf "https://github.com/matrix-org/matrix-spec/tree/%s" $version }} | +| Release date | {{ .Date | time.Format ":date_long" }} | +{{ end -}} + +{{ .RawContent | replaceRE "\n- " "\n- [ ] " }} diff --git a/layouts/docs/changelog.html b/layouts/docs/changelog.html new file mode 100644 index 00000000..b23c8074 --- /dev/null +++ b/layouts/docs/changelog.html @@ -0,0 +1,46 @@ +{{- /* + + Template to render a page with a `changelog` layout or the `changelog` + section page. This conflation seems to be a limitation of Hugo currently, it + uses this template for both cases. + + For the `changelog` section page, this redirects the page to the latest + version's changelog page. + + For a page with a `changelog` layout, this adds a table at the top of the + page with information about the release: + + * A link to the matrix-spec repository at the time of the release, with the + version taken from the `linkTitle` in the frontmatter of the page, unless + it is the unstable changelog. + * The date of the release, taken from the `date` in the frontmatter of the + page, unless it is the unstable changelog. + * A link to the markdown checklist format of the changelog. The `outputs` in + the frontmatter of the page must include `checklist`. + +*/ -}} + +{{ define "main" }} +{{ if .IsSection -}} + {{ with index .RegularPages.ByDate.Reverse 0 -}} + + {{ end -}} +{{ else -}} + {{ $version := lower .LinkTitle -}} +
+

{{ .Title }}

+ + + {{ if ne $version "unstable" -}} + {{ $commitLink := printf "https://github.com/matrix-org/matrix-spec/tree/%s" $version -}} + + + {{ end -}} + {{ $checklist := .OutputFormats.Get "checklist" -}} + +
Git commit{{ $commitLink }}
Release date{{ .Date | time.Format ":date_long" }}
Checklistchecklist.md
+ + {{ .Content }} +
+{{ end -}} +{{ end }} diff --git a/layouts/partials/added-in.html b/layouts/partials/added-in.html index c75c0676..1ab3ad4c 100644 --- a/layouts/partials/added-in.html +++ b/layouts/partials/added-in.html @@ -1,13 +1,13 @@ -{{ $ver := .v }} -{{ $this := .this }} +{{ $ver := .v -}} +{{ $this := .this -}} {{/* This differs from the shortcode added-in by wanting to be a block instead of inline and by slightly altering the rendered text as a result. */}} -{{ if $this }} - **New in this version.** -{{ else }} - **Added in `v{{ $ver }}`** -{{ end }} +{{ if $this -}} +

New in this version.

+{{ else -}} +

Added in v{{ $ver }}

+{{ end -}} diff --git a/layouts/partials/alert.html b/layouts/partials/alert.html index 9096769f..40e13db4 100644 --- a/layouts/partials/alert.html +++ b/layouts/partials/alert.html @@ -15,6 +15,6 @@ {{ $content := .content}} {{ $omit_title := .omit_title }} - - {{ define "partials/version-string" }} {{ $ret := "unstable version"}} diff --git a/layouts/partials/openapi/render-api.html b/layouts/partials/openapi/render-api.html index db10b98c..608cfa33 100644 --- a/layouts/partials/openapi/render-api.html +++ b/layouts/partials/openapi/render-api.html @@ -2,18 +2,19 @@ Render an HTTP API, given: - * `api_data`: the OpenAPI/Swagger data + * `api_data`: the OpenAPI data * `base_url`: the base URL: that is, the part we glue onto the front of each value in `paths` to get a complete URL. - * `path`: the directory under /data where we found this API definition. - We use this to resolve "$ref" values, since they are relative to the schema's - location. + * `anchor_base`: an optional prefix for the HTML IDs generated by + this template. + + This template replaces the old {{*_http_api}} template. */}} {{ $api_data := index .api_data }} {{ $base_url := .base_url }} -{{ $path := .path }} +{{ $anchor_base := .anchor_base }} {{ range $path_name, $path_data := $api_data.paths }} @@ -21,32 +22,32 @@ {{/* note that a `paths` entry can be a $ref */}} - {{ $params := dict "endpoint" $endpoint "path" $path }} + {{ $params := dict "endpoint" $endpoint }} {{ with $path_data.get }} - {{ $operation_params := merge $params (dict "method" "GET" "operation_data" . ) }} + {{ $operation_params := merge $params (dict "method" "GET" "operation_data" . "anchor_base" $anchor_base) }} {{ partial "openapi/render-operation" $operation_params }} {{ end }} {{ with $path_data.post }} - {{ $operation_params := merge $params (dict "method" "POST" "operation_data" . ) }} + {{ $operation_params := merge $params (dict "method" "POST" "operation_data" . "anchor_base" $anchor_base) }} {{ partial "openapi/render-operation" $operation_params }} {{ end }} {{ with $path_data.put }} - {{ $operation_params := merge $params (dict "method" "PUT" "operation_data" . ) }} + {{ $operation_params := merge $params (dict "method" "PUT" "operation_data" . "anchor_base" $anchor_base) }} {{ partial "openapi/render-operation" $operation_params }} {{ end }} {{ with $path_data.delete }} - {{ $operation_params := merge $params (dict "method" "DELETE" "operation_data" . ) }} + {{ $operation_params := merge $params (dict "method" "DELETE" "operation_data" . "anchor_base" $anchor_base) }} {{ partial "openapi/render-operation" $operation_params }} {{ end }} diff --git a/layouts/partials/openapi/render-content-type.html b/layouts/partials/openapi/render-content-type.html index da1a69bd..b1f8239d 100644 --- a/layouts/partials/openapi/render-content-type.html +++ b/layouts/partials/openapi/render-content-type.html @@ -1,27 +1,37 @@ {{/* - Render a table showing content type and description, given: + Render a table showing content types and their descriptions, given: - * `content_type`: the content type as a string - - * `description`: the description as a string + * `content_types`: OpenAPI data specifying the content types as a dictionary of the form {string: {"schema": JsonSchema}} */}} -{{ $content_type := .content_type }} -{{ $description := .description}} +{{ $content_types := .content_types }} -{{ if $content_type }} +{{ if (gt (len $content_types) 0) }} - - + + + + + {{ range $mime, $body := $content_types }} - - + + + {{ end }}
Content-TypeDescription
Content-TypeDescription
{{ $content_type }}{{ $description | markdownify -}}{{ $mime }} + {{/* + Force the rendering as a block so the description is always inside a + paragraph. This allows to always keep the same spacing between paragraphs + when adding added-in and changed-in paragraphs. + */}} + {{ $body.schema.description | page.RenderString (dict "display" "block") -}} + {{ if (index $body.schema "x-addedInMatrixVersion") }}{{ partial "added-in" (dict "v" (index $body.schema "x-addedInMatrixVersion")) }}{{ end -}} + {{ if (index $body.schema "x-changedInMatrixVersion") }}{{ partial "changed-in" (dict "changes_dict" (index $body.schema "x-changedInMatrixVersion")) }}{{ end -}} +
{{ end }} diff --git a/layouts/partials/openapi/render-object-table.html b/layouts/partials/openapi/render-object-table.html index 0f5841a4..08dd5790 100644 --- a/layouts/partials/openapi/render-object-table.html +++ b/layouts/partials/openapi/render-object-table.html @@ -6,10 +6,16 @@ * `anchor`: optional HTML element id for the table - * `properties`: dictionary of the properties to list, each given as: + * `properties`: optional dictionary of the properties to list, each given as: `property_name` : `property_data` - * `required`: array containing the names of required properties. + * `additionalProperties`: a JSON Schema for additional properties on the + object. + + * `patternProperties`: optional dictionary for properties with names adhering + to a regex pattern. A map from regex pattern to JSON Schema. + + * `required`: optional array containing the names of required properties. In some cases (such as response body specifications) this isn't used, and instead properties have a `required` boolean attribute. We support this too. @@ -20,46 +26,19 @@ {{ $required := .required}} {{ if $properties }} - {{ with $title }} {{ . }} {{ end }} - Name - Type - Description + + Name + Type + Description + {{ range $property_name, $property := $properties }} - - {{ $property := partial "json-schema/resolve-allof" $property }} - {{ $type := $property.type }} - - {{ if or (eq $property.type "object") (and $property.oneOf (reflect.IsSlice .oneOf)) }} - {{ $type = partial "type-or-title" $property }} - {{ end }} - - {{/* - If the property is an array, indicate this with square brackets, - like `[type]`. - */}} - {{ if eq $property.type "array"}} - {{ $items := $property.items }} - {{ if $property.items }} - {{ $items = partial "json-schema/resolve-allof" $property.items }} - {{ end }} - {{ $inner_type := partial "type-or-title" $items }} - {{ $type = delimit (slice "[" $inner_type "]") "" }} - {{ end }} - - {{/* - If the property is an enum, indicate this. - */}} - {{ if (and (eq $property.type "string") ($property.enum)) }} - {{ $type = "enum" }} - {{ end }} - {{/* Handle two ways of indicating "required", one for simple parameters, the other for request and response body objects. @@ -68,65 +47,296 @@ {{ $property_name }} - {{ $type }} - - {{ if $required }}Required: {{end -}} - {{ $property.description | markdownify -}} - {{ if eq $type "enum"}}

One of: [{{ delimit $property.enum ", " }}].

{{ end -}} - {{ if (index $property "x-addedInMatrixVersion") }}{{ partial "added-in" (dict "v" (index $property "x-addedInMatrixVersion")) }}{{ end -}} - {{ if (index $property "x-changedInMatrixVersion") }}{{ partial "changed-in" (dict "changes_dict" (index $property "x-changedInMatrixVersion")) }}{{ end -}} - + {{ partial "partials/property-type" $property | safeHTML }} + {{ partial "partials/property-description" (dict "property" $property "required" $required) }} {{ end }} + {{/* + If the object has additional properties *as well as* regular properties, we add a special row to the table. + + Note that, per https://json-schema.org/draft/2020-12/json-schema-core#name-boolean-json-schemas, JSON schemas + can be a simple "true" or "false" as well as the more normal object. + + `additionalProperties: true` is pretty much the default for Matrix (it means: "you're allowed to include random + unspecced properties in your object"), so nothing to do here. + + `additionalProperties: false` means "you're not allowed to include any unspecced properties in your object". We + may want to consider how to display that; for now we just ignore it. + + TODO: support `patternProperties` here. + */}} + {{ if reflect.IsMap .additionalProperties }} + + + <Other properties> + {{ partial "partials/property-type" .additionalProperties | safeHTML }} + {{ partial "partials/property-description" (dict "property" .additionalProperties) }} + + {{ end }} + + +{{ else if (or .additionalProperties .patternProperties) }} + +{{/* +A special format of table for objects which only have additionalProperties or patternProperties. + +This is only ever used for top-level objects. Nested objects in this situation are just shown +as rows within their parent object, and don't get their own table. (They are filtered out in +resolve-additional-types.) +*/}} + + + {{ with $title }} + {{ . }} + {{ end }} + + + Type + Description + + + + {{ $property := . }} + + + {{ partial "partials/property-type" $property | safeHTML }} + {{ partial "partials/property-description" (dict "property" $property) }} + {{ end }} {{/* - Picks either the `title` of a property, or the `type`, to turn into the rendered type field. - Also handles `additionalProperties`, if no `title` is present. + Computes the type to display for a property's schema, given: + + * `type`: optional string or array of strings for the type(s) of the property + + * `title`: optional string for the title of the property + + * `oneOf`: optional array of dictionaries describing the different formats + that the property can have + + * `anyOf`: optional array of dictionaries describing the different formats + that the property can have + + * `properties`: if the type is an object, optional dictionary for + well-defined properties, each given as: `property_name` : `property_data` + + * `additionalProperties`: if the type is an object, optional dictionary for + properties with undefined names + + * `patternProperties`: if the type is an object, optional dictionary for + properties with names adhering to a regex pattern + + * `items`: if the type is an array, array of dictionaries describing the + format of the array's items + + * `anchor`: optional HTML element id for the target type, which will be used to link to it. + + * `format`: optional string for the format of the type, used for strings. + */}} -{{ define "partials/type-or-title" }} +{{ define "partials/property-type" }} {{ $type := "" }} - {{ if .title }} + + {{ if eq .type "object" }} + {{/* Resolve the type or title of the object */}} + {{ $type = partial "object-type-or-title" . }} + {{ else if eq .type "array"}} {{/* - If the property has a `title`, use that rather than `type`. - This means we can write things like `EventFilter` rather than `object`. + If the property is an array, indicate this with square brackets, + like `[type]`. */}} - {{ $type = .title }} + {{ $items := .items }} + {{ $inner_type := partial "property-type" $items }} + {{ $type = delimit (slice "[" $inner_type "]") "" }} + {{ else if eq .type "string" }} + {{ $type = "string" }} + + {{/* If the string uses a known format, use it. */}} + {{ with .format }} + {{ with partial "string-format" . }} + {{ $type = . }} + {{ end }} + {{ end }} + {{ else if or (reflect.IsSlice .type) .oneOf .anyOf }} + {{/* + It's legal to specify an array of types. + + There are three ways to do that: + - Use an array of strings. + - Use oneOf, with items having a schema. + - Use anyOf, with items having a schema. + + Join them together in that case, like `type|other_type`. + */}} + {{ $types := slice }} + + {{ if .oneOf }} + {{ range .oneOf }} + {{ $types = $types | append (partial "property-type" .) }} + {{ end }} + {{ else if .anyOf }} + {{ range .anyOf }} + {{ $types = $types | append (partial "property-type" .) }} + {{ end }} + {{ else }} + {{ range .type }} + {{ $types = $types | append (htmlEscape .) }} + {{ end }} + {{ end }} + + {{ $type = delimit $types "|" }} + {{ else }} + {{/* A simple type like integer or boolean */}} + {{ $type = (htmlEscape .type) }} + {{ end }} + + {{ return $type }} +{{ end }} + +{{/* + Computes the type to display for an object property's schema, given: + + * `type`: string equal to "object" + + * `title`: optional string for the title of the object property + + * `properties`: optional dictionary for well-defined properties, each given + as: `property_name` : `property_data` + + * `additionalProperties`: optional dictionary for properties with undefined + names + + * `patternProperties`: optional dictionary for properties with names + adhering to a regex pattern + + * `anchor`: optional HTML element id for the target type, which will be used to link to it. +*/}} +{{ define "partials/object-type-or-title" }} + {{ $type := "object" }} + {{ if .properties }} + {{/* + The object has its own (regular) properties, so we will make a + separate table for it. Refer to it using its title, if it has one. + */}} + {{ if .title }} + {{ $type = .title | htmlEscape }} + {{ if .anchor }} + {{ $type = printf "%s" (htmlEscape .anchor) $type }} + {{ end }} + {{ end }} {{ else if reflect.IsMap .additionalProperties }} {{/* If the property uses `additionalProperties` to describe its internal structure, handle this with a bit of recursion */}} - {{ $type = delimit (slice "{string: " (partial "type-or-title" .additionalProperties) "}" ) "" }} - {{ else if reflect.IsSlice .type }} - {{/* It's legal to specify an array of types. Join them together in that case */}} - - {{ $types := slice }} - - {{ range .type }} - {{ $types = $types | append . }} - {{ end }} - - {{ $type = delimit $types "|" }} - {{ else if and .oneOf (reflect.IsSlice .oneOf) }} + {{ $type = delimit (slice "{string: " (partial "property-type" .additionalProperties) "}" ) "" }} + {{ else if reflect.IsMap .patternProperties }} {{/* - This is like an array of types except some of the types probably have a schema. - Join them together too. + If the property uses `patternProperties` to describe its + internal structure, handle this with a bit of recursion. + Types are grouped by pattern format. Note that we ignore + patterns without a format as the current definitions + always have a single pattern, but we might need to handle + them later to differentiate schemas according to patterns. */}} - {{ $types := slice }} + {{/* + Construct a map from format ID to the type string of the format. + */}} + {{ $formatMap := newScratch }} - {{ range .oneOf }} - {{ $types = $types | append (partial "type-or-title" .) }} + {{ range $pattern, $schema := .patternProperties }} + {{ $formatId := or (index $schema "x-pattern-format") "string" }} + + {{ if $formatMap.Get $formatId }} + {{ errorf "'%s' pattern format is defined more than once for the same property" $formatId }} + {{ end }} + + {{ $formatMap.Set $formatId (partial "property-type" $schema) }} {{ end }} + {{/* First generate the type string for each format. */}} + {{ $types := slice }} + {{ range $formatId, $formatType := $formatMap.Values }} + {{ $formatKey := "string" }} + {{ if ne $formatId "string" }} + {{ with partial "string-format" $formatId }} + {{ $formatKey = . }} + {{ else }} + {{ errorf "Unsupported value for `x-pattern-format`: %s" $formatId }} + {{ end }} + {{ end }} + + {{ $formatString := printf "{%s: %s}" $formatKey $formatType }} + {{ $types = $types | append $formatString }} + {{ end }} + + {{/* Then join all the formats. */}} {{ $type = delimit $types "|" }} - {{ else }} - {{ $type = .type }} + {{ else if .title }} + {{/* + No properties, so there won't be a separate table. We use the title + anyway, because showing the title (like `EventFilter`) is better + than showing `object`. + */}} + {{ $type = .title | htmlEscape }} {{ end }} + {{ return $type }} {{ end }} + +{{/* + Computes the description to display for a property, given: + + * `required`: boolean indicating whether this property is required. + + * `property`: dictionary describing the property's data, with these fields: + + * `description`: string describing the property + + * `enum`: optional array indicating the accepted values for the property + + * `x-addedInMatrixVersion`: optional string indicating in which Matrix + spec version this property was added. + + * `x-changedInMatrixVersion`: optional string indicating in which Matrix + spec version this property was last changed. +*/}} +{{ define "partials/property-description" -}} + {{ $description := .property.description -}} + {{ if .required -}} + {{/* + Prepend "Required:" to make it part of the first paragraph of the + description. + */}} + {{- $description = printf "Required: %s" (default "" $description) -}} + {{ end -}} + {{/* + Force the rendering as a block so the description is always inside a + paragraph. This allows to always keep the same spacing between paragraphs + when adding added-in and changed-in paragraphs. + */}} + {{ $description | page.RenderString (dict "display" "block") -}} + {{ if .property.enum }}

One of: [{{ delimit .property.enum ", " }}].

{{ end -}} + {{ if (index .property "x-addedInMatrixVersion") }}{{ partial "added-in" (dict "v" (index .property "x-addedInMatrixVersion")) }}{{ end -}} + {{ if (index .property "x-changedInMatrixVersion") }}{{ partial "changed-in" (dict "changes_dict" (index .property "x-changedInMatrixVersion")) }}{{ end -}} +{{ end }} + + +{{/* + Computes the type to display for a string format, given the identifier of + the format as a string. +*/}} +{{ define "partials/string-format" }} + {{ $stringFormat := "" }} + + {{ with index site.Data "string-formats" . }} + {{ $stringFormat = printf "%s" (htmlEscape .url | relURL) (htmlEscape .title) }} + {{ end }} + + {{ return $stringFormat }} +{{ end }} diff --git a/layouts/partials/openapi/render-operation.html b/layouts/partials/openapi/render-operation.html index 6486f39c..7869a42b 100644 --- a/layouts/partials/openapi/render-operation.html +++ b/layouts/partials/openapi/render-operation.html @@ -4,8 +4,9 @@ * `method`: the method, e.g. GET, PUT * `endpoint`: the endpoint - * `operation_data`: the OpenAPI/Swagger data for the operation - * `path`: the path where this definition was found, to enable us to resolve "$ref" + * `operation_data`: the OpenAPI data for the operation + * `anchor_base`: an optional prefix for the HTML IDs generated by + this template. This template renders the operation as a `
` containing: @@ -21,21 +22,26 @@ {{ $method := .method }} {{ $endpoint := .endpoint }} {{ $operation_data := .operation_data }} -{{ $path := .path }} -{{ $anchor := anchorize $endpoint }} -
+{{ $anchor := "" }} +{{ if .anchor_base }} + {{ $anchor = printf "%s_" .anchor_base }} +{{ end }} +{{ $anchor = printf "%s%s%s" $anchor (lower $method) (anchorize $endpoint) }} + +
-

- {{ $method }} +

+ {{ $method }} {{ $endpoint }} + {{ template "_default/_markup/td-heading-self-link.html" $anchor }}

-
+
{{ if $operation_data.deprecated }} {{ partial "alert" (dict "type" "warning" "omit_title" "true" "content" "This API is deprecated and will be removed from a future release.") }} @@ -48,7 +54,7 @@ {{ partial "changed-in" (dict "changes_dict" (index $operation_data "x-changedInMatrixVersion")) }} {{ end -}} -

{{ $operation_data.description | markdownify }}

+{{ $operation_data.description | page.RenderString (dict "display" "block") }} @@ -59,14 +65,30 @@ - + {{/* + Authentication is defined with the `security` key. We assume that the + key is not set if no authentication is necessary. If the key is set, + authentication is required unless it contains an item that is an empty + object. + */}} + {{ $requires_authentication := "Yes" }} + {{ if $operation_data.security }} + {{ range $operation_data.security }} + {{ if eq (len (index $operation_data.security 0)) 0 }} + {{ $requires_authentication = "Optional" }} + {{ end }} + {{ end }} + {{ else }} + {{ $requires_authentication = "No" }} + {{ end }} +
Requires authentication:{{ if $operation_data.security }}Yes{{ else }}No{{ end }}{{ $requires_authentication }}
-
-{{ partial "openapi/render-request" (dict "parameters" $operation_data.parameters "request_body" $operation_data.requestBody "path" $path "anchor_base" $anchor ) }} -
-{{ partial "openapi/render-responses" (dict "responses" $operation_data.responses "path" $path "anchor_base" $anchor ) }} +
+{{ partial "openapi/render-request" (dict "parameters" $operation_data.parameters "request_body" $operation_data.requestBody "anchor_base" $anchor ) }} +
+{{ partial "openapi/render-responses" (dict "responses" $operation_data.responses "anchor_base" $anchor ) }}
diff --git a/layouts/partials/openapi/render-parameters.html b/layouts/partials/openapi/render-parameters.html index 0e643a25..1cd263a3 100644 --- a/layouts/partials/openapi/render-parameters.html +++ b/layouts/partials/openapi/render-parameters.html @@ -2,7 +2,7 @@ Render the parameters of a given type, given: - * `parameters`: OpenAPI/Swagger data specifying the parameters + * `parameters`: OpenAPI data specifying the parameters * `type`: the type of parameters to render: "header, ""path", "query" * `caption`: caption to use for the table @@ -32,5 +32,4 @@ {{/* and render the parameters */}} {{ partial "openapi/render-object-table" (dict "title" $caption "properties" $param_dict) }} - {{ end }} diff --git a/layouts/partials/openapi/render-request.html b/layouts/partials/openapi/render-request.html index ce31943c..80b352c6 100644 --- a/layouts/partials/openapi/render-request.html +++ b/layouts/partials/openapi/render-request.html @@ -2,9 +2,8 @@ Render the request part of a single HTTP API operation, given: - * `parameters`: OpenAPI/Swagger data specifying the parameters - * `request_body`: OpenAPI/Swagger data specifying the request body - * `path`: the path where this definition was found, to enable us to resolve "$ref" + * `parameters`: OpenAPI data specifying the parameters + * `request_body`: OpenAPI data specifying the request body * `anchor_base`: a prefix to add to the HTML anchors generated for each object This template renders: @@ -16,8 +15,8 @@ {{ $parameters := .parameters }} {{ $request_body := .request_body }} -{{ $path := .path }} {{ $anchor_base := .anchor_base }} +{{ $anchor := printf "%s_request" $anchor_base }}

Request

@@ -42,11 +41,9 @@ {{/* Display the JSON schemas */}} - {{ $schema := partial "json-schema/resolve-refs" (dict "schema" $json_body.schema "path" $path) }} - {{ $schema := partial "json-schema/resolve-allof" $schema }} + {{ $schema := $json_body.schema }} - {{ $additional_types := partial "json-schema/resolve-additional-types" (dict "schema" $schema "anchor_base" $anchor_base) }} - {{ $additional_types = uniq $additional_types }} + {{ $additional_types := partial "json-schema/resolve-additional-types" (dict "schema" $schema "anchor_base" $anchor) }} {{ range $additional_types }} {{ partial "openapi/render-object-table" . }} {{ end }} @@ -54,12 +51,7 @@ {{/* Show the content types and description. */}} - {{ $mimes := slice }} - {{ range $mime, $body := $request_body.content }} - {{ $mimes = $mimes | append $mime }} - {{ end }} - {{ $content_type := delimit $mimes "|"}} - {{ partial "openapi/render-content-type" (dict "content_type" $content_type "description" $request_body.description) }} + {{ partial "openapi/render-content-type" (dict "content_types" $request_body.content) }} {{ end }}

Request body example

@@ -70,10 +62,7 @@ {{ $example := dict }} {{ if $body.schema }} - {{ $schema := partial "json-schema/resolve-refs" (dict "schema" $body.schema "path" $path) }} - {{ $schema := partial "json-schema/resolve-allof" $schema }} - - {{ $example = partial "json-schema/resolve-example" $schema }} + {{ $example = partial "json-schema/resolve-example" $body.schema }} {{ end }} {{ if and (eq ($example | len) 0) $body.example }} diff --git a/layouts/partials/openapi/render-responses.html b/layouts/partials/openapi/render-responses.html index 37538b6e..084e9481 100644 --- a/layouts/partials/openapi/render-responses.html +++ b/layouts/partials/openapi/render-responses.html @@ -2,8 +2,7 @@ Render the response part of a single HTTP API operation, given: - * `responses`: OpenAPI/Swagger data specifying the responses - * `path`: the path where this definition was found, to enable us to resolve "$ref" + * `responses`: OpenAPI data specifying the responses * `anchor_base`: a prefix to add to the HTML anchors generated for each object This template renders: @@ -15,15 +14,16 @@ */}} {{ $responses := .responses }} -{{ $path := .path }} {{ $anchor_base := .anchor_base }}

Responses

- - + + + + {{ range $code, $response := $responses }} @@ -39,7 +39,26 @@ {{ range $code, $response := $responses }} {{ if $response.content }} + {{ $anchor := printf "%s_response-%s" $anchor_base $code }}

{{$code}} response

+ {{/* Display defined headers */}} + {{ if $response.headers }} + {{/* build a dict mapping from name->schema, which render-object-table expects */}} + {{ $headers_dict := dict }} + {{ range $header_name,$header_props := $response.headers }} + {{/* + merge the schema at the same level as the rest of the other fields because that is + what `render-object-table` expects. Put the schema first so examples in it are + overwritten. + */}} + {{ $header_schema := merge $header_props.schema $header_props }} + {{ $headers_dict = merge $headers_dict (dict $header_name $header_schema )}} + {{ end }} + + {{/* and render the headers */}} + {{ partial "openapi/render-object-table" (dict "title" "Headers" "properties" $headers_dict) }} + {{ end }} + {{/* A response can have several content types. */}} @@ -49,8 +68,7 @@ Display the JSON schemas */}} - {{ $schema := partial "json-schema/resolve-refs" (dict "schema" $json_body.schema "path" $path) }} - {{ $schema := partial "json-schema/resolve-allof" $schema }} + {{ $schema := $json_body.schema }} {{/* All this is to work out how to express the content of the response @@ -80,8 +98,7 @@ response. (This will be a no-op for response types which aren't objects or arrays.) */}} - {{ $additional_types := partial "json-schema/resolve-additional-types" (dict "schema" $schema "anchor_base" $anchor_base) }} - {{ $additional_types = uniq $additional_types }} + {{ $additional_types := partial "json-schema/resolve-additional-types" (dict "schema" $schema "anchor_base" $anchor) }} {{ range $additional_types }} {{ partial "openapi/render-object-table" . }} {{ end }} @@ -92,8 +109,7 @@ {{ if or (eq $schema.type "object") (eq $schema.type "array") }} {{ $example := partial "json-schema/resolve-example" $schema }} {{ if $json_body.examples }} - {{ $example = partial "json-schema/resolve-refs" (dict "schema" $json_body.examples "path" $path) }} - {{ $example = $example.response.value }} + {{ $example = $json_body.examples.response.value }} {{ end }} {{ $example_json := jsonify (dict "indent" " ") $example }} @@ -108,14 +124,7 @@ {{/* Show the content types and description. */}} - {{ $mimes := slice }} - {{ $desc := "" }} - {{ range $mime, $body := $response.content }} - {{ $mimes = $mimes | append $mime }} - {{ $desc = $body.schema.description }} - {{ end }} - {{ $content_type := delimit $mimes "|"}} - {{ partial "openapi/render-content-type" (dict "content_type" $content_type "description" $desc) }} + {{ partial "openapi/render-content-type" (dict "content_types" $response.content) }} {{ end }} {{ end }} {{ end }} diff --git a/layouts/partials/sidebar-tree.html b/layouts/partials/sidebar-tree.html new file mode 100644 index 00000000..dba63f3a --- /dev/null +++ b/layouts/partials/sidebar-tree.html @@ -0,0 +1,88 @@ +{{- /* + + A modified version of the siderbar-tree.html partial in Docsy, adding: + + * The "toc.html" partial at L45. + +*/ -}} + +{{/* We cache this partial for bigger sites and set the active class client side. */ -}} +{{ $sidebarCacheLimit := .Site.Params.ui.sidebar_cache_limit | default 2000 -}} +{{ $shouldDelayActive := ge (len .Site.Pages) $sidebarCacheLimit -}} +
+ {{ if not .Site.Params.ui.sidebar_search_disable -}} + + {{ partial "search-input.html" . }} + + + {{ else -}} +
+ + {{ partial "search-input.html" . }} + + +
+
+ {{ end -}} + +
+{{ define "section-tree-nav-section" -}} +{{ $s := .section -}} +{{ $p := .page -}} +{{ $shouldDelayActive := .shouldDelayActive -}} +{{ $sidebarMenuTruncate := .sidebarMenuTruncate -}} +{{ $treeRoot := cond (eq .ulNr 0) true false -}} +{{ $ulNr := .ulNr -}} +{{ $ulShow := .ulShow -}} +{{ $active := and (not $shouldDelayActive) (eq $s $p) -}} +{{ $activePath := and (not $shouldDelayActive) (or (eq $p $s) ($p.IsDescendant $s)) -}} +{{ $show := cond (or (lt $ulNr $ulShow) $activePath (and (not $shouldDelayActive) (eq $s.Parent $p.Parent)) (and (not $shouldDelayActive) (eq $s.Parent $p)) (not $p.Site.Params.ui.sidebar_menu_compact) (and (not $shouldDelayActive) ($p.IsDescendant $s.Parent))) true false -}} +{{ $mid := printf "m-%s" ($s.RelPermalink | anchorize) -}} +{{ $pages_tmp := where (union $s.Pages $s.Sections).ByWeight ".Params.toc_hide" "!=" true -}} +{{ $pages := $pages_tmp | first $sidebarMenuTruncate -}} +{{ $truncatedEntryCount := sub (len $pages_tmp) $sidebarMenuTruncate -}} +{{ if gt $truncatedEntryCount 0 -}} + {{ warnf "WARNING: %d sidebar entries have been truncated. To avoid this, increase `params.ui.sidebar_menu_truncate` to at least %d (from %d) in your config file. Section: %s" + $truncatedEntryCount (len $pages_tmp) $sidebarMenuTruncate $s.Path -}} +{{ end -}} +{{ $withChild := gt (len $pages) 0 -}} +{{ $manualLink := cond (isset $s.Params "manuallink") $s.Params.manualLink ( cond (isset $s.Params "manuallinkrelref") (relref $s $s.Params.manualLinkRelref) $s.RelPermalink) -}} +{{ $manualLinkTitle := cond (isset $s.Params "manuallinktitle") $s.Params.manualLinkTitle $s.Title -}} +
  • + {{ if (and $p.Site.Params.ui.sidebar_menu_foldable (ge $ulNr 1)) -}} + + + {{ else -}} + {{ with $s.Params.Icon}}{{ end }}{{ $s.LinkTitle }} + {{- end }} + {{- if $withChild }} + {{- $ulNr := add $ulNr 1 }} +
      + {{ range $pages -}} + {{ if (not (and (eq $s $p.Site.Home) (eq .Params.toc_root true))) -}} + {{ template "section-tree-nav-section" (dict "page" $p "section" . "shouldDelayActive" $shouldDelayActive "sidebarMenuTruncate" $sidebarMenuTruncate "ulNr" $ulNr "ulShow" $ulShow) }} + {{- end }} + {{- end }} +
    + {{- end }} +
  • +{{- end -}} diff --git a/layouts/partials/toc.html b/layouts/partials/toc.html new file mode 100644 index 00000000..318335f2 --- /dev/null +++ b/layouts/partials/toc.html @@ -0,0 +1,15 @@ +{{/* + + A modified version of the toc.html partial in Docsy. + +*/}} +{{ $page := .Params }} +{{ if not .Params.notoc -}} + {{ with .TableOfContents -}} +
    +
    + {{ $page.Title }} + {{ . }} +
    + {{ end -}} +{{ end -}} diff --git a/layouts/shortcodes/added-in.html b/layouts/shortcodes/added-in.html index 149be685..855810e9 100644 --- a/layouts/shortcodes/added-in.html +++ b/layouts/shortcodes/added-in.html @@ -1,8 +1,9 @@ -{{ $ver := .Params.v }} -{{ $this := .Params.this }} +{{- $ver := .Params.v -}} -{{ if $this }} - [New in this version] -{{ else }} - [Added in v{{ $ver }}] -{{ end }} {{/* Do not leave an empty line at the end of this file otherwise the inline behaviour breaks. */}} +{{- with page.Params.version -}} + {{- if eq $ver . -}} + [New in this version] + {{- end -}} +{{- else -}} + [Added in v{{ $ver }}] +{{- end -}} diff --git a/layouts/shortcodes/boxes/added-in-paragraph.html b/layouts/shortcodes/boxes/added-in-paragraph.html deleted file mode 100644 index 20ca3932..00000000 --- a/layouts/shortcodes/boxes/added-in-paragraph.html +++ /dev/null @@ -1,22 +0,0 @@ -{{/* - - "Temporary" shortcode for rendering paragraphs which want/need inline added-in tags. It is - assumed that your content is described as follows: - - {{% boxes/added-in-paragraph %}} - {{< added-in v="1.4" >}} Your text here - - {{< added-in v="1.4" >}} Your other text here - {{% /boxes/added-in-paragraph %}} - - The assumption is that at a later date this added-in-paragraph shortcode can be removed, making - the angle bracket-defined added-in shortcodes *just work*. - - It is important that each new "content" paragraph (the bit after added-in) is preceded with - and added-in, otherwise you might find your text being weirdly merged. - - This exists while the added-in shortcode cannot be inline in the client-server spec. - See https://github.com/matrix-org/matrix-spec/issues/1204 - -*/}} -{{ partial "alert" (dict "type" "added-in-paragraph" "content" .Inner) }} diff --git a/layouts/shortcodes/changed-in.html b/layouts/shortcodes/changed-in.html index 8da2559a..6e4716e0 100644 --- a/layouts/shortcodes/changed-in.html +++ b/layouts/shortcodes/changed-in.html @@ -1,8 +1,9 @@ -{{ $ver := .Params.v }} -{{ $this := .Params.this }} +{{- $ver := .Params.v -}} -{{ if $this }} - [Changed in this version] -{{ else }} - [Changed in v{{ $ver }}] -{{ end }} {{/* Do not leave an empty line at the end of this file otherwise the inline behaviour breaks. */}} +{{- with page.Params.version -}} + {{- if eq $ver . -}} + [Changed in this version] + {{- end -}} +{{- else -}} + [Changed in v{{ $ver }}] +{{- end -}} diff --git a/layouts/shortcodes/changelog/changelog-description.html b/layouts/shortcodes/changelog/changelog-description.html deleted file mode 100644 index 3c719725..00000000 --- a/layouts/shortcodes/changelog/changelog-description.html +++ /dev/null @@ -1,19 +0,0 @@ -{{/* - - This template is used to provide different content for the unstable spec - version and for a versioned release. - -*/}} - -{{ $status := .Site.Params.version.status }} - -{{ if eq $status "unstable"}} - -

    This is the unstable version of the Matrix specification.

    -

    This changelog lists changes made since the last release of the specification.

    - -{{ else }} - -

    This is version v{{ .Site.Params.version.major }}.{{ .Site.Params.version.minor }} of the Matrix specification.

    - -{{ end }} diff --git a/layouts/shortcodes/changelog/changelogs.html b/layouts/shortcodes/changelog/changelogs.html deleted file mode 100644 index 78b5932f..00000000 --- a/layouts/shortcodes/changelog/changelogs.html +++ /dev/null @@ -1,10 +0,0 @@ -{{/* - This template is used to render all of the changelog sections under - "content/changelogs" -*/}} - -{{ with .Page.Resources.Match "*.md" }} -{{ range ((sort . "Params.date" "desc")) }} -{{ .Content }} -{{ end }} -{{ end }} diff --git a/layouts/shortcodes/cs-module.html b/layouts/shortcodes/cs-module.html index 475ebd48..52c9a5d9 100644 --- a/layouts/shortcodes/cs-module.html +++ b/layouts/shortcodes/cs-module.html @@ -11,6 +11,6 @@ {{ with .Site.GetPage "client-server-api/modules" }} {{ with .Resources.GetMatch (printf "%s%s" $name ".md") }} -{{ .Content }} +{{ .RenderShortcodes }} {{ end }} {{ end }} diff --git a/layouts/shortcodes/definition.html b/layouts/shortcodes/definition.html index 67cd63c0..10ad0e87 100644 --- a/layouts/shortcodes/definition.html +++ b/layouts/shortcodes/definition.html @@ -22,15 +22,13 @@ {{ errorf "site data %s not found" $path }} {{ end }} -{{/* The base path, which we use to resolve $ref, omits the last component */}} -{{ $pieces = first (sub (len $pieces) 1) $pieces}} -{{ $path = delimit $pieces "/" }} - {{/* Resolve $ref and allOf */}} {{ $definition = partial "json-schema/resolve-refs" (dict "schema" $definition "path" $path) }} {{ $definition = partial "json-schema/resolve-allof" $definition }} -
    +{{ $anchor_base := printf "definition-%s" (anchorize $definition.title) }} + +
    @@ -41,7 +39,7 @@ -
    +
    {{ if (index $definition "x-addedInMatrixVersion") }} {{ partial "added-in" (dict "v" (index $definition "x-addedInMatrixVersion")) }} @@ -50,8 +48,11 @@ {{ $definition.description | markdownify }} -{{ $additional_types := partial "json-schema/resolve-additional-types" (dict "schema" $definition "name" (printf "\"%s\"" $path)) }} -{{ $additional_types = uniq $additional_types }} +{{ $additional_types := partial "json-schema/resolve-additional-types" (dict + "schema" $definition + "anchor_base" $anchor_base + "name" (printf "\"%s\"" $path)) +}} {{ range $additional_types }} {{ partial "openapi/render-object-table" . }} @@ -65,4 +66,6 @@ {{ jsonify (dict "indent" " ") $example }} ``` +
    +
    diff --git a/layouts/shortcodes/diagram.html b/layouts/shortcodes/diagram.html new file mode 100644 index 00000000..5e2dadd3 --- /dev/null +++ b/layouts/shortcodes/diagram.html @@ -0,0 +1,53 @@ +{{- /* + + This template is used to render an image representing a diagram. + + It takes the following parameters: + + * `name` (required): the file name without extension. + * `alt` (required): a textual replacement for the image, useful for + accessibility. + + Other requirements for diagrams: + + * They must be located in `/assets/diagrams`. + * They must be WebP images, with a `.webp` file extension. + * They must be rendered at a 200% scale. + + Differences with loading a diagram as a regular markdown image: + + * The diagram is lazy-loaded, which should speed up the loading of the spec. + * The dimensions of the diagram are added to the HTML, allowing the browser + to pre-allocate space before it is loaded. + * The diagram supports devices with high pixel density screens and a WebP + image is generated for the default resolution. + * A PNG fallback image is generated, for maximum browser compatibility. + +*/ -}} + +{{- $name := .Params.name -}} +{{- $alt := .Params.alt -}} + +{{- $path := printf "/diagrams/%s.webp" $name -}} + +{{- with resources.Get $path -}} + {{- $highRes := . -}} + + {{- /* + The high resolution image has a scale of 200% so we need to divide the + dimensions by 2 to get the real one. + */ -}} + {{- $width := div $highRes.Width 2 | string -}} + {{- $height := div $highRes.Width 2 | string -}} + + {{- /* Generate a low resolution WebP and a fallback PNG. */ -}} + {{- $lowRes := $highRes.Resize (printf "%sx webp drawing" $width) -}} + {{- $fallback := $highRes.Resize (printf "%sx png" $width) -}} + + + + {{ $alt }} + +{{- else -}} + {{- errorf "diagram %s not found" $path -}} +{{- end -}} diff --git a/layouts/shortcodes/event-fields.html b/layouts/shortcodes/event-fields.html index 91e2faf2..35085996 100644 --- a/layouts/shortcodes/event-fields.html +++ b/layouts/shortcodes/event-fields.html @@ -13,7 +13,7 @@ */}} {{ $event := index .Site.Data "event-schemas" "schema" "core-event-schema" .Params.event_type }} -{{ $path := "event-schemas/schema/core-event-schema" }} +{{ $path := delimit (slice "event-schemas/schema/core-event-schema" .Params.event_type) "/" }} {{ $event = partial "json-schema/resolve-refs" (dict "schema" $event "path" $path) }} {{ $event := partial "json-schema/resolve-allof" $event }} @@ -28,7 +28,7 @@ -
    +
    {{ $event.description | markdownify }} diff --git a/layouts/shortcodes/event-group.html b/layouts/shortcodes/event-group.html index 5e2900f0..7b80a964 100644 --- a/layouts/shortcodes/event-group.html +++ b/layouts/shortcodes/event-group.html @@ -12,21 +12,26 @@ */}} -{{ $path := "event-schemas/schema" }} +{{ $base_path := "event-schemas/schema" }} -{{ $events := index .Site.Data "event-schemas" "schema" }} {{ $group_name := .Params.group_name }} -{{ range $event_name, $event_data := $events }} - +{{/* Filter events and prepare them for sorting */}} +{{ $events := slice }} +{{ range $event_name, $event_data := index .Site.Data "event-schemas" "schema" }} {{ $prefix := substr $event_name 0 (len $group_name) }} {{ if eq $prefix $group_name }} - - {{ $event_data = partial "json-schema/resolve-refs" (dict "schema" $event_data "path" $path) }} - {{ $event_data := partial "json-schema/resolve-allof" $event_data }} - - {{ partial "events/render-event" (dict "event_name" $event_name "event_data" $event_data)}} - + {{ $events = $events | append (dict "event_name" $event_name "event_data" $event_data) }} {{ end }} +{{ end }} + +{{/* Render the events sorted by x-weight */}} +{{ range sort $events "event_data.x-weight" }} + + {{ $path := delimit (slice $base_path .event_name) "/" }} + {{ $event_data := partial "json-schema/resolve-refs" (dict "schema" .event_data "path" $path) }} + {{ $event_data := partial "json-schema/resolve-allof" $event_data }} + + {{ partial "events/render-event" (dict "event_name" .event_name "event_data" $event_data)}} {{ end }} diff --git a/layouts/shortcodes/event.html b/layouts/shortcodes/event.html index a9838542..c671318a 100644 --- a/layouts/shortcodes/event.html +++ b/layouts/shortcodes/event.html @@ -25,7 +25,7 @@ */}} {{ $event_data := index .Site.Data "event-schemas" "schema" .Params.event }} -{{ $path := "event-schemas/schema" }} +{{ $path := delimit (slice "event-schemas/schema" .Params.event) "/" }} {{ $event_data = partial "json-schema/resolve-refs" (dict "schema" $event_data "path" $path) }} {{ $event_data := partial "json-schema/resolve-allof" $event_data }} diff --git a/layouts/shortcodes/http-api.html b/layouts/shortcodes/http-api.html index 2668b1ab..b5201c49 100644 --- a/layouts/shortcodes/http-api.html +++ b/layouts/shortcodes/http-api.html @@ -1,16 +1,19 @@ {{/* - This template is used to render an HTTP API, given an OpenAPI/Swagger definition. + This template is used to render an HTTP API, given an OpenAPI definition. It expects to be passed two parameters: * a `spec` parameter identifying the spec, which must be the name of a directory under /data/api - * an `api` parameter, identifying an OpenAPI/Swagger definition, + * an `api` parameter, identifying an OpenAPI definition, which is the name of a schema file under "data/api/$spec". The file extension is omitted. For example: {{% http-api spec="server-server" api="public_rooms" %}} + * an optional `anchor_base` parameter, which should be used as a + prefix for the HTML IDs generated by this template. It should only + be necessary to provide one for duplicate endpoints. This template replaces the old {{*_http_api}} template. @@ -18,9 +21,13 @@ {{ $spec := .Params.spec}} {{ $api := .Params.api}} +{{ $anchor_base := .Params.anchor_base}} {{ $api_data := index .Site.Data.api .Params.spec .Params.api }} {{ $base_url := (index $api_data.servers 0).variables.basePath.default }} -{{ $path := delimit (slice "api" $spec) "/" }} +{{ $path := delimit (slice "api" $spec $api) "/" }} -{{ partial "openapi/render-api" (dict "api_data" $api_data "base_url" $base_url "path" $path) }} +{{ $api_data = partial "json-schema/resolve-refs" (dict "schema" $api_data "path" $path) }} +{{ $api_data = partial "json-schema/resolve-allof" $api_data }} + +{{ partial "openapi/render-api" (dict "api_data" $api_data "base_url" $base_url "anchor_base" $anchor_base) }} diff --git a/layouts/shortcodes/msgtypes.html b/layouts/shortcodes/msgtypes.html index ba731111..1ab28aae 100644 --- a/layouts/shortcodes/msgtypes.html +++ b/layouts/shortcodes/msgtypes.html @@ -6,7 +6,6 @@ */}} -{{ $path := "event-schemas/schema" }} {{ $compact := false }} {{/* @@ -40,6 +39,7 @@ {{ range $msgtypes }} {{ $event_data := index $site_data "event-schemas" "schema" . }} + {{ $path := delimit (slice "event-schemas/schema" .) "/" }} {{ $event_data = partial "json-schema/resolve-refs" (dict "schema" $event_data "path" $path) }} {{ $event_data := partial "json-schema/resolve-allof" $event_data }} diff --git a/layouts/shortcodes/proposal-tables.html b/layouts/shortcodes/proposal-tables.html index f61f168b..6f18a50d 100644 --- a/layouts/shortcodes/proposal-tables.html +++ b/layouts/shortcodes/proposal-tables.html @@ -33,7 +33,7 @@ {{ $states := .Site.Data.msc.proposals }} {{ range $states }} -

    {{ .title }}

    +### {{ .title }} {.proposal-table-title} {{ if .proposals }}
    StatusDescription
    StatusDescription
    @@ -68,8 +68,8 @@ - - + + {{ end }} diff --git a/layouts/shortcodes/rver-fragment.html b/layouts/shortcodes/rver-fragment.html index a10be8b5..c0d83e4d 100644 --- a/layouts/shortcodes/rver-fragment.html +++ b/layouts/shortcodes/rver-fragment.html @@ -7,23 +7,12 @@ The `name` parameter is the file name without extension. - The `withVersioning` parameter is optional and defaults to false. When true, any - mentions of "New in this version" from the `added-in` shortcode are removed prior - to rendering. This is useful if needing to use a fragment where part of it describes - new functionality in a given room version but isn't new for subsequent versions. - */}} -{{ $name := .Params.name }} -{{ $withVersioning := .Params.withVersioning }} +{{ $name := .Params.name -}} -{{ with .Site.GetPage "rooms/fragments" }} - {{ with .Resources.GetMatch (printf "%s%s" $name ".md") }} - {{ $content := .Content }} - {{ if not $withVersioning }} - {{ $content = (replace $content "[New in this version]" "") }} - {{ $content = (replace $content "[Changed in this version]" "") }} - {{ end }} -{{ $content | safeHTML }} - {{ end }} -{{ end }} +{{ with .Site.GetPage "rooms/fragments" -}} + {{ with .Resources.GetMatch (printf "%s.md" $name) -}} + {{ .RenderShortcodes | safeHTML }} + {{ end -}} +{{ end -}} diff --git a/meta/documentation_style.rst b/meta/documentation_style.rst index e7b71408..1844f6ec 100644 --- a/meta/documentation_style.rst +++ b/meta/documentation_style.rst @@ -91,12 +91,6 @@ current version is `v1.1` then annotate your changes with `v1.2`. * `{{% added-in v="1.2" %}}` or `{{% changed-in v="1.2" %}}` within Markdown documents. * `x-addedInMatrixVersion` and `x-changedInMatrixVersion` within OpenAPI. -In rare cases, `this=true` can be used on the Markdown syntax to adjust the wording. -This is most commonly used in room version specifications. - -**Tip**: If you're trying to inline the Markdown version and getting unexpected results, -try replacing the `%` symbols with `<` and `>`, changing how Hugo renders the shortcode. - OpenAPI ~~~~~~~ @@ -191,4 +185,4 @@ Describing grammar Use `RFC5234-style ABNF `_ when describing the grammar for something in the spec, such as user IDs or server names. Use lowercase -and underscore-deliminated element names (`user_id`, not `UserID` or `user-id`). +and underscore-delimited element names (`user_id`, not `UserID` or `user-id`). diff --git a/meta/github-labels.rst b/meta/github-labels.rst index 14fb9f69..44c52185 100644 --- a/meta/github-labels.rst +++ b/meta/github-labels.rst @@ -1,7 +1,7 @@ The following labels are used to help categorize issues: `spec-omission `_ --------------------------------------------------------------------------------- +--------------------------------------------------------------------------------- Things which have been implemented but not currently specified. These may range from entire API endpoints, to particular options or return parameters. @@ -17,7 +17,7 @@ Examples: `_ `clarification `_ --------------------------------------------------------------------------------- +--------------------------------------------------------------------------------- An area where the spec could do with being more explicit. @@ -30,7 +30,7 @@ Examples: `_ `spec-bug `_ ----------------------------------------------------------------------- +----------------------------------------------------------------------- Something which is in the spec, but is wrong. @@ -47,7 +47,7 @@ Examples: `_ `improvement `_ ----------------------------------------------------------------------------- +----------------------------------------------------------------------------- A suggestion for a relatively simple improvement to the protocol. @@ -59,7 +59,7 @@ Examples: `_ `feature `_ --------------------------------------------------------------------- +--------------------------------------------------------------------- A suggestion for a significant extension to the matrix protocol which needs considerable consideration before implementation. @@ -72,7 +72,7 @@ Examples: `wart `_ --------------------------------------------------------------- +--------------------------------------------------------------- A point where the protocol is inconsistent or inelegant, but which isn't really causing anybody any problems right now. Might be nice to consider fixing one @@ -80,7 +80,7 @@ day. `question `_ ----------------------------------------------------------------------- +----------------------------------------------------------------------- A thought or idea about the protocol which we aren't really sure whether to pursue or not. diff --git a/meta/releasing.md b/meta/releasing.md index 92dd9be8..273e4eaa 100644 --- a/meta/releasing.md +++ b/meta/releasing.md @@ -6,48 +6,43 @@ machinery works. ## Timeline -The spec is released each calendar quarter. The target release dates are within the -following ranges: +The spec is released each calendar quarter. The *target* months are: -* Q1: January 20-27 (critically, before FOSDEM). -* Q2: May 20-27. -* Q3: August 20-27. -* Q4: November 1-15 (before recurring November conflicts, like IETF). +* Q1: January or February. +* Q2: May. +* Q3: August. +* Q4: November. -The SCT aims to have dates picked out by: - -* Q1: January 10. -* Q2: May 1. -* Q3: August 1. -* Q4: October 15. +The SCT aims to have dates picked out 2 weeks before the chosen release date. When +possible, releases should be scheduled for Thursdays and Fridays to allow a few +consecutive business days for identifying blockers. When a release date is picked, a [checklist](https://github.com/matrix-org/matrix-spec/issues/new?assignees=&labels=release-blocker&projects=&template=release.md&title=Matrix+1.X) -issue is created to track details of the release. Release blockers should continue to -be accepted up until 7 calendar days prior to the release date. +issue is created to track details of the release. Release blockers should continue +to be accepted at the discretion of whoever is doing the release (typically, blockers +should be allowed up to 1-2 days before the release date). **Release dates are not promises.** The SCT reserves the ability to change, cancel, postpone, etc a release for any reason. Do not rely on a release happening on a given day until the release has actually happened & blog post published. -Once a release is scheduled, the SCT will begin planning what the next release is +Once a release is *scheduled*, the SCT will begin planning what the next release is expected to look like. The plan should be included in the spec release blog post, -and be ready for exeuction on spec release day. Plans are guides and not promises. +and be ready for execution on spec release day. Plans are guides and not promises. -A blog post for the SCT members to review should be ready at minimum 1 week before -the target release date. 1-2 days before the release itself, the prerequisite steps -below are executed to ensure the spec release can go ahead. +A blog post for the SCT members to review should be ready 2-3 days prior to the +release at minimum. Preferably a week in advance. + +1-2 days before the release itself, the prerequisite steps below are executed to +ensure the spec release can go ahead. ## Release composition *This section is a work in progress.* -Mentioned above, the SCT aims to have spec releases quarterly. Each quarter has a -slightly different theme to it: - -* Q1: Massive feature release, if possible. This generally happens thanks to FOSDEM. -* Q2: Regular feature release, if possible. -* Q3: Momentum-continuing feature release, if possible. -* Q4: Preferably a maintenance release, but will accept features per normal. +Spec releases do not currently have attached themes, though when planning a release +a broad theme may be considered. Ideally, each release contains a "hero feature" +which is highlighted in the later blog post. ## Prerequisites / preparation @@ -67,7 +62,7 @@ Assuming the preparation work is complete, all that remains is the actual specif release. 1. Create a `release/v1.2` branch where `v1.2` is the version you're about to release. -2. Update the `params.version` section of `config.toml` to use the following template: +2. Update the `params.version` section of `./config/_default/hugo.toml` to use the following template: ```toml [params.version] status = "stable" @@ -84,8 +79,9 @@ release. 3. Commit the changes. 4. Generate the changelog. 1. Activate your python virtual environment. - 2. Run `./scripts/generate-changelog.sh v1.2 "October 01, 2021"` (using the correct - version number and same `release_date` format from the hugo config). + 2. Run `./scripts/generate-changelog.sh v1.2` (using the correct version number). + The script will use the current date. If that date is wrong, correct the document + by using the same `YYYY-MM-DD` date format. 3. Commit the result. 5. Tag the branch with the spec release with a format of `v1.2` (if releasing Matrix 1.2). 6. Push the release branch and the tag. @@ -100,7 +96,7 @@ release. * Upload the artifacts of the GitHub Actions build for the release to the GitHub release as artifacts themselves. This should be the tarball that will be deployed to spec.matrix.org. -10. Commit a reversion to `params.version` of `config.toml` on `main`: +10. Commit a reversion to `params.version` of `./config/_default/hugo.toml` on `main`: ```toml [params.version] status = "unstable" @@ -115,12 +111,16 @@ release. ## Patching a release -From time to time we'll need to update a release in the wild. Examples include fixing typos, -updating build machinery, etc. Typically it is not considered a good idea to patch a release -more than 1 month after the original release date - this is because the administrative effort -is typically best reserved for the next release cycle. +Patch releases are used to fix the most recent release on record. Typically a patch +release will be deployed if there is an issue with the build machinery, a factual +error is introduced by the release, or there are notable clarity issues introduced +by the release which may affect implementation. It's usually not a good idea to +ship a patch release if it can be avoided. -**Patch releases are not to be used for spec changes. Only typos and equivalent.** +Typos and similar do not generally require a patch release. + +**Patch releases must not to be used for spec changes (new MSCs, etc) beyond fixing +factual errors.** 1. Add the required changes to the release branch (`release/v1.2` for example). 2. Fast forward the `v1.2` tag to the release branch head. diff --git a/openapi_extensions.md b/openapi_extensions.md index eba1121c..71b7f063 100644 --- a/openapi_extensions.md +++ b/openapi_extensions.md @@ -1,6 +1,6 @@ # OpenAPI Extensions -For some functionality that is not directly provided by the OpenAPI v2 +For some functionality that is not directly provided by the OpenAPI v3.1 specification, some extensions have been added that are to be consistent across the specification. The defined extensions are listed below. Extensions should not break parsers, however if extra functionality is required, aware @@ -12,56 +12,9 @@ To ease API design and management, the API definition is split across several files. Each of these files is self-contained valid OpenAPI. There is no single root file in the source tree as OpenAPI requires; this file -can be generated by `dump-swagger.py`. The script does not convert -the extensions described further in this document (`oneOf` and parameter -exploding) so there can be minor interoperability issues with tooling that -expects compliant Swagger. - -## Extensible Query Parameters - - - -If a unknown amount of query parameters can be added to a request, the `name` -must be `fields...`, with the trailing ellipses representing the possibility -of more fields. - -Example: - -``` - - in: query - name: fields... - type: string -``` - -## Using oneOf to provide type alternatives - - - -`oneOf` (available in JSON Schema and Swagger/OpenAPI v3 but not in v2) -is used in cases when a simpler type specification as a list of types -doesn't work, as in the following example: -``` - properties: - old: # compliant with old Swagger - type: - - string - - object # Cannot specify a schema here - new: # uses oneOf extension - oneOf: - - type: string - - type: object - title: CustomSchemaForTheWin - properties: - ... -``` - -## OpenAPI 3's "2xx" format for response codes - - - -In some cases, the schema will have HTTP response code definitions like -`2xx`, `3xx`, and `4xx`. These indicate that a response code within those -ranges (`2xx` = `200` to `299`) is valid for the schema. +can be generated by `dump-openapi.py`. The script does not convert +the extensions described further in this document so there can be minor +interoperability issues with tooling that expects compliant OpenAPI. ## Custom `x-addedInMatrixVersion` key @@ -73,3 +26,23 @@ property, etc). A variation of the above: indicates changes to the associated parameter in particular Matrix specification versions. + +## Use of `$ref` inside examples + +Although the OpenAPI/JSON Schema specs only allow to use `$ref` to reference a +whole example, we use it to compose examples from other examples. + +## Custom `x-pattern-format` key and custom formats + +In JSON Schema, [`format`](https://json-schema.org/understanding-json-schema/reference/string#format) +is a property to convey semantic information about a schema. We define +`x-pattern-format` as a key on the schemas under `patternProperties` with the +same use as `format`, but that applies to the pattern of the property. We also +define custom values for formats with the `mx-` prefix in +`data/string-formats.yaml`. The values in this file are recognized in the +rendered specification and link to the definition of the format. + +## Custom `x-weight` key + +This property allows controlling the display order of events rendered with the +`event-group` shortcode. diff --git a/package-lock.json b/package-lock.json index 7b6ba539..7b606b07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,18 +9,137 @@ "version": "0.0.1", "license": "Apache-2.0", "devDependencies": { - "autoprefixer": "^10.4.2", + "@fullhuman/postcss-purgecss": "^6.0.0", + "autoprefixer": "^10.4.20", "node-fetch": "^2.6.7", - "postcss-cli": "^8.2.13" + "postcss": "^8.4.49", + "postcss-cli": "^11.0.0" + } + }, + "node_modules/@fullhuman/postcss-purgecss": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-6.0.0.tgz", + "integrity": "sha512-sUvk5PV7O5xvTJcxDYrQ00xlKtSxivvJdZrwgxE8F1GmNMs7w9U+dSbr83N/qEs9b+f+6QsZKXDs0k8nMjBIqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "purgecss": "^6.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.3", + "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" }, "engines": { @@ -28,27 +147,53 @@ } }, "node_modules/@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.3", + "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" }, "engines": { "node": ">= 8" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -86,35 +231,32 @@ "node": ">= 8" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/autoprefixer": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz", - "integrity": "sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==", + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "browserslist": "^4.19.1", - "caniuse-lite": "^1.0.30001297", - "fraction.js": "^4.1.2", + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -123,14 +265,17 @@ "engines": { "node": "^10 || ^12 || >=14" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": "^8.1.0" } }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, "node_modules/binary-extensions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", @@ -140,50 +285,82 @@ "node": ">=8" } }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", - "escalade": "^3.1.1", - "node-releases": "^2.0.1", - "picocolors": "^1.0.0" + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001306", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001306.tgz", - "integrity": "sha512-Wd1OuggRzg1rbnM5hv1wXs2VkxJH/AA+LuudlIqvZiCvivF+wJJe2mgBZC8gPMgI7D76PP5CTx8Luvaqc1V6OQ==", + "version": "1.0.30001680", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz", + "integrity": "sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" }, "node_modules/chokidar": { "version": "3.4.2", @@ -207,14 +384,17 @@ } }, "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/color-convert": { @@ -235,32 +415,66 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", + "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/dependency-graph": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.9.0.tgz", - "integrity": "sha512-9YLIBURXj4DJMFALxXw9K3Y3rwb5Fk0X5/8ipCzaN84+gKxoHK43tVKRNakCQbiEx07E8Uwhuq21BpUagFhZ8w==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", "dev": true, "engines": { "node": ">= 0.6.0" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.4.63", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.63.tgz", - "integrity": "sha512-e0PX/LRJPFRU4kzJKLvTobxyFdnANCvcoDCe8XcyTqP58nTWIwdsHvXLIl1RkB39X5yaosLaroMASWB0oIsgCA==", - "dev": true + "version": "1.5.62", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.62.tgz", + "integrity": "sha512-t8c+zLmJHa9dJy96yBZRXGQYoiCEnHYgFwn1asvSPZSUdVxnB62A4RASd7k41ytG3ErFBA0TpHlKg9D9SQBmLg==", + "dev": true, + "license": "ISC" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -269,45 +483,48 @@ "dev": true }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", + "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" + "micromatch": "^4.0.4" }, "engines": { - "node": ">=8" + "node": ">=8.6.0" } }, "node_modules/fastq": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", - "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -315,32 +532,50 @@ "node": ">=8" } }, - "node_modules/fraction.js": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz", - "integrity": "sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==", + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "license": "MIT", "engines": { "node": "*" }, "funding": { "type": "patreon", - "url": "https://www.patreon.com/infusion" + "url": "https://github.com/sponsors/rawify" } }, "node_modules/fs-extra": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", - "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dev": true, + "license": "MIT", "dependencies": { - "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", - "universalify": "^1.0.0" + "universalify": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=14.14" } }, "node_modules/fsevents": { @@ -368,17 +603,38 @@ } }, "node_modules/get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -392,36 +648,39 @@ } }, "node_modules/globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", "dev": true, + "license": "MIT", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" }, "node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -473,59 +732,129 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } }, - "node_modules/jsonfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", - "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "universalify": "^1.0.0" + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "node_modules/lilconfig": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", - "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=8" + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" } }, "node_modules/nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, - "peer": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -554,10 +883,11 @@ } }, "node_modules/node-releases": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", - "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", - "dev": true + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, + "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -577,25 +907,64 @@ "node": ">=0.10.0" } }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "engines": { "node": ">=8.6" @@ -614,111 +983,100 @@ } }, "node_modules/postcss": { - "version": "8.4.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", - "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "dev": true, - "peer": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "nanoid": "^3.2.0", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" } }, "node_modules/postcss-cli": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-8.3.1.tgz", - "integrity": "sha512-leHXsQRq89S3JC9zw/tKyiVV2jAhnfQe0J8VI4eQQbUjwIe0XxVqLrR+7UsahF1s9wi4GlqP6SJ8ydf44cgF2Q==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-11.0.0.tgz", + "integrity": "sha512-xMITAI7M0u1yolVcXJ9XTZiO9aO49mcoKQy6pCDFdMh9kGqhzLVpWxeD/32M/QBmkhcGypZFFOLNLmIW4Pg4RA==", "dev": true, + "license": "MIT", "dependencies": { - "chalk": "^4.0.0", "chokidar": "^3.3.0", - "dependency-graph": "^0.9.0", - "fs-extra": "^9.0.0", - "get-stdin": "^8.0.0", - "globby": "^11.0.0", - "postcss-load-config": "^3.0.0", + "dependency-graph": "^0.11.0", + "fs-extra": "^11.0.0", + "get-stdin": "^9.0.0", + "globby": "^14.0.0", + "picocolors": "^1.0.0", + "postcss-load-config": "^5.0.0", "postcss-reporter": "^7.0.0", "pretty-hrtime": "^1.0.3", "read-cache": "^1.0.0", - "slash": "^3.0.0", - "yargs": "^16.0.0" + "slash": "^5.0.0", + "yargs": "^17.0.0" }, "bin": { - "postcss": "bin/postcss" + "postcss": "index.js" }, "engines": { - "node": ">=10" + "node": ">=18" }, "peerDependencies": { "postcss": "^8.0.0" } }, - "node_modules/postcss-cli/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/postcss-cli/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/postcss-cli/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/postcss-load-config": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.1.tgz", - "integrity": "sha512-c/9XYboIbSEUZpiD1UQD0IKiUe8n9WHYV7YFe7X7J+ZwCsEKkUJSFWjS9hBU1RR9THR7jMXst8sxiqP0jjo2mg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-5.1.0.tgz", + "integrity": "sha512-G5AJ+IX0aD0dygOE0yFZQ/huFFMSNneyfp0e3/bT05a8OfPC5FUoZRPfGijUdGOJNMewJiwzcHJXFafFzeKFVA==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "lilconfig": "^2.0.4", - "yaml": "^1.10.2" + "lilconfig": "^3.1.1", + "yaml": "^2.4.2" }, "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">= 18" }, "peerDependencies": { - "ts-node": ">=9.0.0" + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1" }, "peerDependenciesMeta": { - "ts-node": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { "optional": true } } @@ -743,6 +1101,20 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", @@ -758,6 +1130,43 @@ "node": ">= 0.8" } }, + "node_modules/purgecss": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-6.0.0.tgz", + "integrity": "sha512-s3EBxg5RSWmpqd0KGzNqPiaBbWDz1/As+2MzoYVGMqgDqRTLBhJW6sywfTBek7OwNfoS/6pS0xdtvChNhFj2cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^12.0.0", + "glob": "^10.3.10", + "postcss": "^8.4.4", + "postcss-selector-parser": "^6.0.7" + }, + "bin": { + "purgecss": "bin/purgecss.js" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -782,7 +1191,7 @@ "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "engines": { "node": ">=0.10.0" @@ -793,32 +1202,91 @@ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, "node_modules/run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, "engines": { "node": ">=8" } }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, - "peer": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -837,6 +1305,22 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -849,6 +1333,20 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/thenby": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/thenby/-/thenby-1.3.4.tgz", @@ -860,6 +1358,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -873,15 +1372,67 @@ "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", "dev": true }, - "node_modules/universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", "engines": { "node": ">= 10.0.0" } }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -898,6 +1449,22 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -915,6 +1482,25 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -925,69 +1511,160 @@ } }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", + "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" } } }, "dependencies": { - "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "@fullhuman/postcss-purgecss": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-6.0.0.tgz", + "integrity": "sha512-sUvk5PV7O5xvTJcxDYrQ00xlKtSxivvJdZrwgxE8F1GmNMs7w9U+dSbr83N/qEs9b+f+6QsZKXDs0k8nMjBIqA==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.3", + "purgecss": "^6.0.0" + } + }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.3", + "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true + }, + "@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1013,64 +1690,66 @@ "picomatch": "^2.0.4" } }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, "autoprefixer": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz", - "integrity": "sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==", + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", "dev": true, "requires": { - "browserslist": "^4.19.1", - "caniuse-lite": "^1.0.30001297", - "fraction.js": "^4.1.2", + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "postcss-value-parser": "^4.2.0" } }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, "binary-extensions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", "dev": true }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "requires": { - "fill-range": "^7.0.1" + "balanced-match": "^1.0.0" + } + }, + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "requires": { + "fill-range": "^7.1.1" } }, "browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", - "escalade": "^3.1.1", - "node-releases": "^2.0.1", - "picocolors": "^1.0.0" + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" } }, "caniuse-lite": { - "version": "1.0.30001306", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001306.tgz", - "integrity": "sha512-Wd1OuggRzg1rbnM5hv1wXs2VkxJH/AA+LuudlIqvZiCvivF+wJJe2mgBZC8gPMgI7D76PP5CTx8Luvaqc1V6OQ==", + "version": "1.0.30001680", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz", + "integrity": "sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==", "dev": true }, "chokidar": { @@ -1090,13 +1769,13 @@ } }, "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "requires": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, @@ -1115,25 +1794,45 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "dependency-graph": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.9.0.tgz", - "integrity": "sha512-9YLIBURXj4DJMFALxXw9K3Y3rwb5Fk0X5/8ipCzaN84+gKxoHK43tVKRNakCQbiEx07E8Uwhuq21BpUagFhZ8w==", + "commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "cross-spawn": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", + "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", "dev": true, "requires": { - "path-type": "^4.0.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "dev": true + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "electron-to-chromium": { - "version": "1.4.63", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.63.tgz", - "integrity": "sha512-e0PX/LRJPFRU4kzJKLvTobxyFdnANCvcoDCe8XcyTqP58nTWIwdsHvXLIl1RkB39X5yaosLaroMASWB0oIsgCA==", + "version": "1.5.62", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.62.tgz", + "integrity": "sha512-t8c+zLmJHa9dJy96yBZRXGQYoiCEnHYgFwn1asvSPZSUdVxnB62A4RASd7k41ytG3ErFBA0TpHlKg9D9SQBmLg==", "dev": true }, "emoji-regex": { @@ -1143,59 +1842,67 @@ "dev": true }, "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true }, "fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", + "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" + "micromatch": "^4.0.4" } }, "fastq": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", - "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "requires": { "reusify": "^1.0.4" } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "requires": { "to-regex-range": "^5.0.1" } }, + "foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + } + }, "fraction.js": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz", - "integrity": "sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true }, "fs-extra": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", - "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dev": true, "requires": { - "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", - "universalify": "^1.0.0" + "universalify": "^2.0.0" } }, "fsevents": { @@ -1212,11 +1919,25 @@ "dev": true }, "get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", "dev": true }, + "glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + } + }, "glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -1227,29 +1948,29 @@ } }, "globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", "dev": true, "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" } }, "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true }, "is-binary-path": { @@ -1288,20 +2009,42 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, "jsonfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", - "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "requires": { "graceful-fs": "^4.1.6", - "universalify": "^1.0.0" + "universalify": "^2.0.0" } }, "lilconfig": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", - "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true + }, + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true }, "merge2": { @@ -1311,21 +2054,35 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "braces": "^3.0.3", + "picomatch": "^2.3.1" } }, - "nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "peer": true + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true + }, + "nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true }, "node-fetch": { "version": "2.6.7", @@ -1337,9 +2094,9 @@ } }, "node-releases": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", - "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, "normalize-path": { @@ -1354,22 +2111,44 @@ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", "dev": true }, + "package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "requires": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + } + }, "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", "dev": true }, "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true }, "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, "pify": { @@ -1379,72 +2158,44 @@ "dev": true }, "postcss": { - "version": "8.4.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", - "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "dev": true, - "peer": true, "requires": { - "nanoid": "^3.2.0", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" } }, "postcss-cli": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-8.3.1.tgz", - "integrity": "sha512-leHXsQRq89S3JC9zw/tKyiVV2jAhnfQe0J8VI4eQQbUjwIe0XxVqLrR+7UsahF1s9wi4GlqP6SJ8ydf44cgF2Q==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-11.0.0.tgz", + "integrity": "sha512-xMITAI7M0u1yolVcXJ9XTZiO9aO49mcoKQy6pCDFdMh9kGqhzLVpWxeD/32M/QBmkhcGypZFFOLNLmIW4Pg4RA==", "dev": true, "requires": { - "chalk": "^4.0.0", "chokidar": "^3.3.0", - "dependency-graph": "^0.9.0", - "fs-extra": "^9.0.0", - "get-stdin": "^8.0.0", - "globby": "^11.0.0", - "postcss-load-config": "^3.0.0", + "dependency-graph": "^0.11.0", + "fs-extra": "^11.0.0", + "get-stdin": "^9.0.0", + "globby": "^14.0.0", + "picocolors": "^1.0.0", + "postcss-load-config": "^5.0.0", "postcss-reporter": "^7.0.0", "pretty-hrtime": "^1.0.3", "read-cache": "^1.0.0", - "slash": "^3.0.0", - "yargs": "^16.0.0" - }, - "dependencies": { - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "slash": "^5.0.0", + "yargs": "^17.0.0" } }, "postcss-load-config": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.1.tgz", - "integrity": "sha512-c/9XYboIbSEUZpiD1UQD0IKiUe8n9WHYV7YFe7X7J+ZwCsEKkUJSFWjS9hBU1RR9THR7jMXst8sxiqP0jjo2mg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-5.1.0.tgz", + "integrity": "sha512-G5AJ+IX0aD0dygOE0yFZQ/huFFMSNneyfp0e3/bT05a8OfPC5FUoZRPfGijUdGOJNMewJiwzcHJXFafFzeKFVA==", "dev": true, "requires": { - "lilconfig": "^2.0.4", - "yaml": "^1.10.2" + "lilconfig": "^3.1.1", + "yaml": "^2.4.2" } }, "postcss-reporter": { @@ -1457,6 +2208,16 @@ "thenby": "^1.3.4" } }, + "postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, "postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", @@ -1469,6 +2230,24 @@ "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, + "purgecss": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-6.0.0.tgz", + "integrity": "sha512-s3EBxg5RSWmpqd0KGzNqPiaBbWDz1/As+2MzoYVGMqgDqRTLBhJW6sywfTBek7OwNfoS/6pS0xdtvChNhFj2cw==", + "dev": true, + "requires": { + "commander": "^12.0.0", + "glob": "^10.3.10", + "postcss": "^8.4.4", + "postcss-selector-parser": "^6.0.7" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -1490,7 +2269,7 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true }, "reusify": { @@ -1500,23 +2279,46 @@ "dev": true }, "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true }, "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", "dev": true }, "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "peer": true + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true }, "string-width": { "version": "4.2.3", @@ -1529,6 +2331,17 @@ "strip-ansi": "^6.0.1" } }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -1538,6 +2351,15 @@ "ansi-regex": "^5.0.1" } }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "thenby": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/thenby/-/thenby-1.3.4.tgz", @@ -1559,10 +2381,32 @@ "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", "dev": true }, + "unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true + }, "universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true + }, + "update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "requires": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, "webidl-conversions": { @@ -1581,6 +2425,15 @@ "webidl-conversions": "^3.0.0" } }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -1592,6 +2445,17 @@ "strip-ansi": "^6.0.0" } }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -1599,30 +2463,30 @@ "dev": true }, "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", + "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", "dev": true }, "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "requires": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" } }, "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true } } diff --git a/package.json b/package.json index f023a750..e1233d0c 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,6 @@ "main": "none.js", "scripts": { "get-proposals": "node ./scripts/proposals.js", - "get:submodule": "git submodule update --init --depth 1", - "_prepare:docsy": "cd themes/docsy && npm install", - "prepare": "npm run get:submodule && npm run _prepare:docsy", "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { @@ -22,9 +19,10 @@ }, "homepage": "https://github.com/matrix-org/matrix-spec#readme", "devDependencies": { - "autoprefixer": "^10.4.2", + "@fullhuman/postcss-purgecss": "^6.0.0", + "autoprefixer": "^10.4.20", "node-fetch": "^2.6.7", - "postcss-cli": "^9.1.0", - "postcss": "^8.4.6" + "postcss": "^8.4.49", + "postcss-cli": "^11.0.0" } } diff --git a/packages/npm/.gitignore b/packages/npm/.gitignore new file mode 100644 index 00000000..133fcabd --- /dev/null +++ b/packages/npm/.gitignore @@ -0,0 +1,2 @@ +node_modules +sas-emoji.json diff --git a/packages/npm/package.json b/packages/npm/package.json new file mode 100644 index 00000000..d305fda9 --- /dev/null +++ b/packages/npm/package.json @@ -0,0 +1,13 @@ +{ + "name": "@matrix-org/spec", + "version": "0.0.0", + "description": "Data definitions for the Matrix Spec", + "author": "matrix.org", + "license": "Apache-2.0", + "files": [ + "sas-emoji.json" + ], + "scripts": { + "prepare": "cp ../../data-definitions/sas-emoji.json ." + } +} diff --git a/packages/npm/yarn.lock b/packages/npm/yarn.lock new file mode 100644 index 00000000..fb57ccd1 --- /dev/null +++ b/packages/npm/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 00000000..ecd78497 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,15 @@ +// Remove unused CSS selectors. +const purgecss = require('@fullhuman/postcss-purgecss')({ + // Use stats generated by Hugo. + content: [ './hugo_stats.json' ], + defaultExtractor: (content) => { + let els = JSON.parse(content).htmlElements; + return els.tags.concat(els.classes, els.ids); + } +}); + +module.exports = { + plugins: [ + ...(process.env.HUGO_ENVIRONMENT === 'production' ? [ purgecss ] : []) + ] + }; diff --git a/redocly.yaml b/redocly.yaml index 263f0bca..28dda2db 100644 --- a/redocly.yaml +++ b/redocly.yaml @@ -1,10 +1,11 @@ # See https://redocly.com/docs/cli/configuration/ for more information. extends: - - minimal + - recommended-strict rules: info-license: off security-defined: off operation-4xx-response: off no-invalid-media-type-examples: off no-path-trailing-slash: off - operation-2xx-response: off \ No newline at end of file + operation-2xx-response: off + spec-strict-refs: error \ No newline at end of file diff --git a/scripts/check-event-schema-examples.py b/scripts/check-event-schema-examples.py index c6191321..fae129f6 100755 --- a/scripts/check-event-schema-examples.py +++ b/scripts/check-event-schema-examples.py @@ -1,5 +1,9 @@ #!/usr/bin/env python -# + +# Validates the examples under `../data/event_schemas` against their JSON +# schemas. In the process, the JSON schemas are validated against the JSON +# Schema 2020-12 specification. + # Copyright 2016 OpenMarket Ltd # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,6 +18,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import helpers import sys import json import os @@ -37,6 +42,12 @@ except ImportError as e: import_error("jsonschema", "jsonschema", "jsonschema", e) raise +try: + import referencing +except ImportError as e: + import_error("referencing", "referencing", "referencing", e) + raise + try: import yaml except ImportError as e: @@ -44,55 +55,22 @@ except ImportError as e: raise -def load_file(path): - print("Loading reference: %s" % path) - if not path.startswith("file://"): - raise Exception("Bad ref: %s" % (path,)) - path = path[len("file://"):] - with open(path, "r") as f: - if path.endswith(".json"): - return json.load(f) - else: - # We have to assume it's YAML because some of the YAML examples - # do not have file extensions. - return yaml.safe_load(f) - - -def resolve_references(path, schema): - if isinstance(schema, dict): - # do $ref first - if '$ref' in schema: - value = schema['$ref'] - path = os.path.abspath(os.path.join(os.path.dirname(path), value)) - ref = load_file("file://" + path) - result = resolve_references(path, ref) - del schema['$ref'] - else: - result = {} - - for key, value in schema.items(): - result[key] = resolve_references(path, value) - return result - elif isinstance(schema, list): - return [resolve_references(path, value) for value in schema] - else: - return schema - - def check_example_file(examplepath, schemapath): with open(examplepath) as f: - example = resolve_references(examplepath, json.load(f)) + example = helpers.resolve_references(examplepath, json.load(f)) with open(schemapath) as f: schema = yaml.safe_load(f) + # $id as a URI with scheme is necessary to make registry resolver work. fileurl = "file://" + os.path.abspath(schemapath) - schema["id"] = fileurl - resolver = jsonschema.RefResolver(fileurl, schema, handlers={"file": load_file}) + schema["$id"] = fileurl print ("Checking schema for: %r %r" % (examplepath, schemapath)) try: - jsonschema.validate(example, schema, resolver=resolver) + registry = referencing.Registry(retrieve=helpers.load_resource_from_uri) + validator = jsonschema.validators.Draft202012Validator(schema, registry=registry) + validator.validate(example) except Exception as e: raise ValueError("Error validating JSON schema for %r %r" % ( examplepath, schemapath diff --git a/scripts/check-json-schemas.py b/scripts/check-json-schemas.py new file mode 100755 index 00000000..5e0ceaa3 --- /dev/null +++ b/scripts/check-json-schemas.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 + +# Validates the JSON schemas under `../data`. The schemas are validated against +# the JSON Schema 2020-12 specification, and their inline examples and default +# values are validated against the schema. + +# Copyright 2023 Kévin Commaille +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import helpers +import sys +import json +import os +import traceback + + +def import_error(module, package, debian, error): + sys.stderr.write(( + "Error importing %(module)s: %(error)r\n" + "To install %(module)s run:\n" + " pip install %(package)s\n" + "or on Debian run:\n" + " sudo apt-get install python-%(debian)s\n" + ) % locals()) + if __name__ == '__main__': + sys.exit(1) + +try: + import jsonschema +except ImportError as e: + import_error("jsonschema", "jsonschema", "jsonschema", e) + raise + +try: + import referencing +except ImportError as e: + import_error("referencing", "referencing", "referencing", e) + raise + +try: + import yaml +except ImportError as e: + import_error("yaml", "PyYAML", "yaml", e) + raise + +try: + import jsonpath +except ImportError as e: + import_error("jsonpath", "python-jsonpath", "jsonpath", e) + raise + +try: + import attrs +except ImportError as e: + import_error("attrs", "attrs", "attrs", e) + raise + +@attrs.define +class SchemaDirReport: + files: int = 0 + errors: int = 0 + + def add(self, other_report): + self.files += other_report.files + self.errors += other_report.errors + +def check_example(path, schema, example): + # $id as a URI with scheme is necessary to make registry resolver work. + fileurl = "file://" + os.path.abspath(path) + schema["$id"] = fileurl + + registry = referencing.Registry(retrieve=helpers.load_resource_from_uri) + validator = jsonschema.validators.Draft202012Validator(schema, registry=registry) + + validator.validate(example) + +def check_schema_examples(path, full_schema): + """Search objects with inline examples in the schema and check they validate + against the object's definition. + """ + errors = [] + matches = jsonpath.finditer( + # Recurse through all objects and filter out those that don't have an + # `example`, `examples` or `default` field. + "$..[?(@.example != undefined || @.examples != undefined || @.default != undefined)]", + full_schema + ) + + for match in matches: + schema = match.obj + if "example" in schema: + try: + check_example(path, schema, schema["example"]) + except Exception as e: + example_path = f"{match.path}['example']" + print(f"Failed to validate example at {example_path}: {e}") + errors.append(e) + + if "examples" in schema: + for index, example in enumerate(schema["examples"]): + try: + check_example(path, schema, example) + except Exception as e: + example_path = f"{match.path}['examples'][{index}]" + print(f"Failed to validate example at {example_path}: {e}") + errors.append(e) + + if "default" in schema: + try: + check_example(path, schema, schema["default"]) + except Exception as e: + example_path = f"{match.path}['default']" + print(f"Failed to validate example at {example_path}: {e}") + errors.append(e) + + if len(errors) > 0: + raise Exception(errors) + + +def check_schema_file(schema_path): + with open(schema_path) as f: + schema = yaml.safe_load(f) + + print(f"Checking schema: {schema_path}") + + # Check schema is valid. + try: + validator = jsonschema.validators.Draft202012Validator + validator.check_schema(schema) + except Exception as e: + print(f"Failed to validate JSON schema: {e}") + raise + + # Check schema examples are valid. + check_schema_examples(schema_path, schema) + +def check_schema_dir(schemadir: str) -> SchemaDirReport: + report = SchemaDirReport() + for root, dirs, files in os.walk(schemadir): + for schemadir in dirs: + dir_report = check_schema_dir(os.path.join(root, schemadir)) + report.add(dir_report) + for filename in files: + if filename.startswith("."): + # Skip over any vim .swp files. + continue + if filename.endswith(".json"): + # Skip over any explicit examples (partial event definitions) + continue + try: + report.files += 1 + check_schema_file(os.path.join(root, filename)) + except Exception as e: + report.errors += 1 + return report + +# The directory that this script is residing in. +script_dir = os.path.dirname(os.path.realpath(__file__)) +# The directory of the project. +project_dir = os.path.abspath(os.path.join(script_dir, "../")) +print(f"Project dir: {project_dir}") + +# Directories to check, relative to the data folder. +schema_dirs = [ + "api/application-service/definitions", + "api/client-server/definitions", + "api/identity/definitions", + "api/server-server/definitions", + "event-schemas/schema", + "schemas", +] + +report = SchemaDirReport() +for schema_dir in schema_dirs: + dir_report = check_schema_dir(os.path.join(project_dir, "data", schema_dir)) + report.add(dir_report) + +print(f"Found {report.errors} errors in {report.files} files") + +if report.errors: + sys.exit(1) + diff --git a/scripts/check-openapi-sources.py b/scripts/check-openapi-sources.py new file mode 100755 index 00000000..4ba0392e --- /dev/null +++ b/scripts/check-openapi-sources.py @@ -0,0 +1,181 @@ +#! /usr/bin/env python + +# Validates the OpenAPI definitions under `../data/api`. Checks the request +# parameters and body, and response body. The schemas are validated against the +# JSON Schema 2020-12 specification and the examples are validated against those +# schemas. + +# Copyright 2016 OpenMarket Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import helpers +import sys +import json +import os + + +def import_error(module, package, debian, error): + sys.stderr.write(( + "Error importing %(module)s: %(error)r\n" + "To install %(module)s run:\n" + " pip install %(package)s\n" + "or on Debian run:\n" + " sudo apt-get install python-%(debian)s\n" + ) % locals()) + if __name__ == '__main__': + sys.exit(1) + +try: + import jsonschema +except ImportError as e: + import_error("jsonschema", "jsonschema", "jsonschema", e) + raise + +try: + import referencing +except ImportError as e: + import_error("referencing", "referencing", "referencing", e) + raise + +try: + import yaml +except ImportError as e: + import_error("yaml", "PyYAML", "yaml", e) + raise + + +def check_schema(filepath, example, schema): + # $id as a URI with scheme is necessary to make registry resolver work. + schema["$id"] = filepath + + registry = referencing.Registry(retrieve=helpers.load_resource_from_uri) + validator = jsonschema.validators.Draft202012Validator(schema, registry=registry) + validator.validate(example) + + +def check_parameter(filepath, request, parameter): + schema = parameter.get('schema') + example = parameter.get('example') + + if not example: + example = schema.get('example') + + if example and schema: + try: + print("Checking schema for request parameter: %r %r %r" % ( + filepath, request, parameter.get("name") + )) + check_schema(filepath, example, schema) + except Exception as e: + raise ValueError("Error validating JSON schema for %r" % ( + request + ), e) + +def check_request_body(filepath, request, body): + schema = body.get('schema') + example = body.get('example') + + if not example: + example = schema.get('example') + + if example and schema: + try: + print("Checking schema for request body: %r %r" % ( + filepath, request, + )) + check_schema(filepath, example, schema) + except Exception as e: + raise ValueError("Error validating JSON schema for %r" % ( + request + ), e) + + +def check_response(filepath, request, code, response): + schema = response.get('schema') + if schema: + for name, example in response.get('examples', {}).items(): + value = example.get('value') + if value: + try: + print ("Checking response schema for: %r %r %r %r" % ( + filepath, request, code, name + )) + check_schema(filepath, value, schema) + except jsonschema.SchemaError as error: + for suberror in sorted(error.context, key=lambda e: e.schema_path): + print(list(suberror.schema_path), suberror.message, sep=", ") + raise ValueError("Error validating JSON schema for %r %r" % ( + request, code + ), e) + except Exception as e: + raise ValueError("Error validating JSON schema for %r %r" % ( + request, code + ), e) + + +def check_openapi_file(filepath): + with open(filepath) as f: + openapi = yaml.safe_load(f) + + openapi = helpers.resolve_references(filepath, openapi) + + openapi_version = openapi.get('openapi') + if not openapi_version: + # This is not an OpenAPI file, skip. + return + elif openapi_version != '3.1.0': + raise ValueError("File %r is not using the proper OpenAPI version: expected '3.1.0', got %r" % (filepath, openapi_version)) + + for path, path_api in openapi.get('paths', {}).items(): + + for method, request_api in path_api.items(): + request = "%s %s" % (method.upper(), path) + for parameter in request_api.get('parameters', ()): + check_parameter(filepath, request, parameter) + + json_body = request_api.get('requestBody', {}).get('content', {}).get('application/json') + if json_body: + check_request_body(filepath, request, json_body) + + try: + responses = request_api['responses'] + except KeyError: + raise ValueError("No responses for %r" % (request,)) + for code, response in responses.items(): + json_response = response.get('content', {}).get('application/json') + + if json_response: + check_response(filepath, request, code, json_response) + + +if __name__ == '__main__': + # Get the directory that this script is residing in + script_directory = os.path.dirname(os.path.realpath(__file__)) + + # Resolve the directory containing the OpenAPI sources, + # relative to the script path + source_files_directory = os.path.realpath(os.path.join(script_directory, "../data/api")) + + # Walk the source path directory, looking for YAML files to check + for (root, dirs, files) in os.walk(source_files_directory): + for filename in files: + if not filename.endswith(".yaml"): + continue + + path = os.path.join(root, filename) + + try: + check_openapi_file(path) + except Exception as e: + raise ValueError("Error checking file %s" % (path,), e) diff --git a/scripts/check-swagger-sources.py b/scripts/check-swagger-sources.py deleted file mode 100755 index 39e27f24..00000000 --- a/scripts/check-swagger-sources.py +++ /dev/null @@ -1,187 +0,0 @@ -#! /usr/bin/env python -# -# Copyright 2016 OpenMarket Ltd -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys -import json -import os - - -def import_error(module, package, debian, error): - sys.stderr.write(( - "Error importing %(module)s: %(error)r\n" - "To install %(module)s run:\n" - " pip install %(package)s\n" - "or on Debian run:\n" - " sudo apt-get install python-%(debian)s\n" - ) % locals()) - if __name__ == '__main__': - sys.exit(1) - -try: - import jsonschema -except ImportError as e: - import_error("jsonschema", "jsonschema", "jsonschema", e) - raise - -try: - import yaml -except ImportError as e: - import_error("yaml", "PyYAML", "yaml", e) - raise - - -def check_schema(filepath, example, schema): - example = resolve_references(filepath, example) - schema = resolve_references(filepath, schema) - resolver = jsonschema.RefResolver(filepath, schema, handlers={"file": load_file}) - jsonschema.validate(example, schema, resolver=resolver) - - -def check_parameter(filepath, request, parameter): - schema = parameter.get("schema") - example = schema.get('example') - - if example and schema: - try: - print("Checking request schema for: %r %r" % ( - filepath, request - )) - check_schema(filepath, example, schema) - except Exception as e: - raise ValueError("Error validating JSON schema for %r" % ( - request - ), e) - - -def check_response(filepath, request, code, response): - example = response.get('examples', {}).get('application/json') - schema = response.get('schema') - if example and schema: - try: - print ("Checking response schema for: %r %r %r" % ( - filepath, request, code - )) - check_schema(filepath, example, schema) - except jsonschema.SchemaError as error: - for suberror in sorted(error.context, key=lambda e: e.schema_path): - print(list(suberror.schema_path), suberror.message, sep=", ") - raise ValueError("Error validating JSON schema for %r %r" % ( - request, code - ), e) - except Exception as e: - raise ValueError("Error validating JSON schema for %r %r" % ( - request, code - ), e) - - -def check_swagger_file(filepath): - with open(filepath) as f: - swagger = yaml.safe_load(f) - - for path, path_api in swagger.get('paths', {}).items(): - - for method, request_api in path_api.items(): - request = "%s %s" % (method.upper(), path) - for parameter in request_api.get('parameters', ()): - if parameter['in'] == 'body': - check_parameter(filepath, request, parameter) - - try: - responses = request_api['responses'] - except KeyError: - raise ValueError("No responses for %r" % (request,)) - for code, response in responses.items(): - check_response(filepath, request, code, response) - - -def resolve_references(path, schema): - """Recurse through a given schema until we find a $ref key. Upon doing so, - check that the referenced file exists, then load it up and check all of the - references in that file. Continue on until we've hit all dead ends. - - $ref values are deleted from schemas as they are validated, to prevent - duplicate work. - """ - if isinstance(schema, dict): - # do $ref first - if '$ref' in schema: - # Pull the referenced filepath from the schema - referenced_file = schema['$ref'] - - # Referenced filepaths are relative, so take the current path's - # directory and append the relative, referenced path to it. - inner_path = os.path.join(os.path.dirname(path), referenced_file) - - # Then convert the path (which may contiain '../') into a - # normalised, absolute path - inner_path = os.path.abspath(inner_path) - - # Load the referenced file - ref = load_file("file://" + inner_path) - - # Check that the references in *this* file are valid - result = resolve_references(inner_path, ref) - - # They were valid, and so were the sub-references. Delete - # the reference here to ensure we don't pass over it again - # when checking other files - del schema['$ref'] - else: - result = {} - - for key, value in schema.items(): - result[key] = resolve_references(path, value) - return result - elif isinstance(schema, list): - return [resolve_references(path, value) for value in schema] - else: - return schema - - -def load_file(path): - print("Loading reference: %s" % path) - if not path.startswith("file://"): - raise Exception("Bad ref: %s" % (path,)) - path = path[len("file://"):] - with open(path, "r") as f: - if path.endswith(".json"): - return json.load(f) - else: - # We have to assume it's YAML because some of the YAML examples - # do not have file extensions. - return yaml.safe_load(f) - - -if __name__ == '__main__': - # Get the directory that this script is residing in - script_directory = os.path.dirname(os.path.realpath(__file__)) - - # Resolve the directory containing the swagger sources, - # relative to the script path - source_files_directory = os.path.realpath(os.path.join(script_directory, "../data")) - - # Walk the source path directory, looking for YAML files to check - for (root, dirs, files) in os.walk(source_files_directory): - for filename in files: - if not filename.endswith(".yaml"): - continue - - path = os.path.join(root, filename) - - try: - check_swagger_file(path) - except Exception as e: - raise ValueError("Error checking file %s" % (path,), e) diff --git a/scripts/dump-swagger.py b/scripts/dump-openapi.py similarity index 80% rename from scripts/dump-swagger.py rename to scripts/dump-openapi.py index ce97c4c3..490ac9bf 100755 --- a/scripts/dump-swagger.py +++ b/scripts/dump-openapi.py @@ -1,9 +1,8 @@ #!/usr/bin/env python3 -# dump-swagger reads all of the swagger API docs used in spec generation and -# outputs a JSON file which merges them all, for use as input to a swagger UI +# dump-openapi reads all of the OpenAPI docs used in spec generation and +# outputs a JSON file which merges them all, for use as input to an OpenAPI # viewer. -# See https://github.com/swagger-api/swagger-ui for details of swagger-ui. # Copyright 2016 OpenMarket Ltd # @@ -21,6 +20,7 @@ import argparse import errno +import helpers import json import logging import os.path @@ -32,34 +32,6 @@ import yaml scripts_dir = os.path.dirname(os.path.abspath(__file__)) api_dir = os.path.join(os.path.dirname(scripts_dir), "data", "api") -def resolve_references(path, schema): - if isinstance(schema, dict): - # do $ref first - if '$ref' in schema: - value = schema['$ref'] - previous_path = path - path = os.path.join(os.path.dirname(path), value) - try: - with open(path, encoding="utf-8") as f: - ref = yaml.safe_load(f) - result = resolve_references(path, ref) - del schema['$ref'] - path = previous_path - except FileNotFoundError: - print("Resolving {}".format(schema)) - print("File not found: {}".format(path)) - result = {} - else: - result = {} - - for key, value in schema.items(): - result[key] = resolve_references(path, value) - return result - elif isinstance(schema, list): - return [resolve_references(path, value) for value in schema] - else: - return schema - def prefix_absolute_path_references(text, base_url): """Adds base_url to absolute-path references. @@ -85,7 +57,7 @@ def edit_links(node, base_url): edit_links(item, base_url) parser = argparse.ArgumentParser( - "dump-swagger.py - assemble the Swagger specs into a single JSON file" + "dump-openapi.py - assemble the OpenAPI specs into a single JSON file" ) parser.add_argument( "--base-url", "-b", @@ -114,7 +86,7 @@ parser.add_argument( ) parser.add_argument( "-o", "--output", - default=os.path.join(scripts_dir, "swagger", "api-docs.json"), + default=os.path.join(scripts_dir, "openapi", "api-docs.json"), help="File to write the output to. Default: %(default)s" ) args = parser.parse_args() @@ -177,7 +149,7 @@ for filename in os.listdir(selected_api_dir): print("Reading OpenAPI: %s" % filepath) with open(filepath, "r") as f: api = yaml.safe_load(f.read()) - api = resolve_references(filepath, api) + api = helpers.resolve_references(filepath, api) basePath = api['servers'][0]['variables']['basePath']['default'] for path, methods in api["paths"].items(): diff --git a/scripts/generate-changelog.sh b/scripts/generate-changelog.sh index 45132619..678af60f 100755 --- a/scripts/generate-changelog.sh +++ b/scripts/generate-changelog.sh @@ -1,12 +1,26 @@ # /bin/bash -# Usage: ./scripts/generate-changelog.sh v1.2 "April 01, 2021" -# or: ./scripts/generate-changelog.sh vUNSTABLE +# Usage: ./scripts/generate-changelog.sh v1.2 for changelogs of stable releases +# or: ./scripts/generate-changelog.sh vUNSTABLE for the unstable changelog. set -e VERSION="$1" -DATE="$2" + +if [ -z "$VERSION" ]; then + echo "ERROR: The version of the changelog must be provided" + exit 1 +fi + +if [ "$VERSION" = "vUNSTABLE" ]; then + TITLE="Changes since last release" + LINKTITLE="Unstable" + FILENAME="unstable.md" +else + TITLE="$VERSION Changelog" + LINKTITLE="$VERSION" + FILENAME="$VERSION.md" +fi cd `dirname $0`/../changelogs @@ -22,18 +36,19 @@ towncrier --yes # to sort the changelogs at build time. cat < ../content/changelog/$VERSION.md +} > ../content/changelog/$FILENAME # Cleanup rm -v rendered.md diff --git a/scripts/helpers.py b/scripts/helpers.py new file mode 100755 index 00000000..a30b2831 --- /dev/null +++ b/scripts/helpers.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 + +# Helpers to resolve $ref recursively in OpenAPI and JSON schemas. + +# Copyright 2016 OpenMarket Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import os +import os.path +import referencing +import urllib.parse +import yaml + +def resolve_references(path, schema): + """Recurse through a given schema until we find a $ref key. Upon doing so, + check that the referenced file exists, then load it up and check all of the + references in that file. Continue on until we've hit all dead ends. + + $ref values are deleted from schemas as they are validated, to prevent + duplicate work. + """ + if isinstance(schema, dict): + # do $ref first + if '$ref' in schema: + # Pull the referenced URI from the schema + ref_uri = schema['$ref'] + + # Join the referenced URI with the URI of the file, to resolve + # relative URIs + full_ref_uri = urllib.parse.urljoin("file://" + path, ref_uri) + + # Separate the fragment. + (full_ref_uri, fragment) = urllib.parse.urldefrag(full_ref_uri) + + # Load the referenced file + ref = load_file_from_uri(full_ref_uri) + + if fragment: + # The fragment should be a JSON Pointer + keys = fragment.strip('/').split('/') + for key in keys: + ref = ref[key] + + # Check that the references in *this* file are valid + result = resolve_references(urllib.parse.urlsplit(full_ref_uri).path, ref) + + # They were valid, and so were the sub-references. Delete + # the reference here to ensure we don't pass over it again + # when checking other files + del schema['$ref'] + else: + result = {} + + for key, value in schema.items(): + result[key] = resolve_references(path, value) + return result + elif isinstance(schema, list): + return [resolve_references(path, value) for value in schema] + else: + return schema + + +def load_file_from_uri(path): + """Load a JSON or YAML file from a file:// URI. + """ + print("Loading reference: %s" % path) + if not path.startswith("file://"): + raise Exception("Bad ref: %s" % (path,)) + path = path[len("file://"):] + with open(path, "r") as f: + if path.endswith(".json"): + return json.load(f) + else: + # We have to assume it's YAML because some of the YAML examples + # do not have file extensions. + return yaml.safe_load(f) + +def load_resource_from_uri(path): + """Load a JSON or YAML JSON Schema, as a `referencing.Resource` object, from + a file:// URI. + """ + contents = load_file_from_uri(path) + resource = referencing.Resource( + contents=contents, + specification=referencing.jsonschema.DRAFT202012 + ) + return resource diff --git a/scripts/swagger-http-server.py b/scripts/openapi-http-server.py similarity index 89% rename from scripts/swagger-http-server.py rename to scripts/openapi-http-server.py index 06d764aa..1865e6c8 100755 --- a/scripts/swagger-http-server.py +++ b/scripts/openapi-http-server.py @@ -1,7 +1,7 @@ #!/usr/bin/env python -# Runs an HTTP server on localhost:8000 which will serve the generated swagger -# JSON so that it can be viewed in an online swagger UI. +# Runs an HTTP server on localhost:8000 which will serve the generated OpenAPI +# JSON so that it can be viewed in an online OpenAPI viewer. # Copyright 2016 OpenMarket Ltd # @@ -41,13 +41,13 @@ if __name__ == '__main__': help='TCP port to listen on (default: %(default)s)', ) parser.add_argument( - 'swagger_dir', nargs='?', - default=os.path.join(scripts_dir, 'swagger'), + 'openapi_dir', nargs='?', + default=os.path.join(scripts_dir, 'openapi'), help='directory to serve (default: %(default)s)', ) args = parser.parse_args() - os.chdir(args.swagger_dir) + os.chdir(args.openapi_dir) httpd = socketserver.TCPServer(("localhost", args.port), MyHTTPRequestHandler) diff --git a/scripts/swagger-preview.html b/scripts/openapi-preview.html similarity index 100% rename from scripts/swagger-preview.html rename to scripts/openapi-preview.html diff --git a/scripts/requirements.txt b/scripts/requirements.txt index 0349d87f..4d508bf4 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -1,9 +1,12 @@ # no doubt older versions would be fine for many of these but these were # current at the time of writing -# we need at least version 4.0.0 for support of JSON Schema Draft 2020-12. -jsonschema == 4.17.3 +# we need at least version 4.18.0 for support of referencing library. +jsonschema >= 4.18.0 +referencing >= 0.28.4 +python-jsonpath >= 1.0.0 +attrs >= 23.1.0 PyYAML >= 3.12 requests >= 2.18.4 towncrier == 23.6.0 diff --git a/static/css/fonts/Inter.css b/static/css/fonts/Inter.css deleted file mode 100644 index c308cb83..00000000 --- a/static/css/fonts/Inter.css +++ /dev/null @@ -1,168 +0,0 @@ -/* cyrillic-ext */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 300; - src: url(../../fonts/Inter-cyrillic-ext-normal-300.woff2); - unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; -} -/* cyrillic */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 300; - src: url(../../fonts/Inter-cyrillic-normal-300.woff2); - unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; -} -/* greek-ext */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 300; - src: url(../../fonts/Inter-greek-ext-normal-300.woff2); - unicode-range: U+1F00-1FFF; -} -/* greek */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 300; - src: url(../../fonts/Inter-greek-normal-300.woff2); - unicode-range: U+0370-03FF; -} -/* vietnamese */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 300; - src: url(../../fonts/Inter-vietnamese-normal-300.woff2); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} -/* latin-ext */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 300; - src: url(../../fonts/Inter-latin-ext-normal-300.woff2); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 300; - src: url(../../fonts/Inter-latin-normal-300.woff2); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* cyrillic-ext */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 400; - src: url(../../fonts/Inter-cyrillic-ext-normal-400.woff2); - unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; -} -/* cyrillic */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 400; - src: url(../../fonts/Inter-cyrillic-normal-400.woff2); - unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; -} -/* greek-ext */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 400; - src: url(../../fonts/Inter-greek-ext-normal-400.woff2); - unicode-range: U+1F00-1FFF; -} -/* greek */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 400; - src: url(../../fonts/Inter-greek-normal-400.woff2); - unicode-range: U+0370-03FF; -} -/* vietnamese */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 400; - src: url(../../fonts/Inter-vietnamese-normal-400.woff2); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} -/* latin-ext */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 400; - src: url(../../fonts/Inter-latin-ext-normal-400.woff2); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 400; - src: url(../../fonts/Inter-latin-normal-400.woff2); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* cyrillic-ext */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 700; - src: url(../../fonts/Inter-cyrillic-ext-normal-700.woff2); - unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; -} -/* cyrillic */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 700; - src: url(../../fonts/Inter-cyrillic-normal-700.woff2); - unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; -} -/* greek-ext */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 700; - src: url(../../fonts/Inter-greek-ext-normal-700.woff2); - unicode-range: U+1F00-1FFF; -} -/* greek */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 700; - src: url(../../fonts/Inter-greek-normal-700.woff2); - unicode-range: U+0370-03FF; -} -/* vietnamese */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 700; - src: url(../../fonts/Inter-vietnamese-normal-700.woff2); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} -/* latin-ext */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 700; - src: url(../../fonts/Inter-latin-ext-normal-700.woff2); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -/* latin */ -@font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 700; - src: url(../../fonts/Inter-latin-normal-700.woff2); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} diff --git a/static/diagrams/membership.png b/static/diagrams/membership.png deleted file mode 100644 index 76198015..00000000 Binary files a/static/diagrams/membership.png and /dev/null differ diff --git a/static/diagrams/threaded-dag-threads.png b/static/diagrams/threaded-dag-threads.png deleted file mode 100644 index 4cf865ed..00000000 Binary files a/static/diagrams/threaded-dag-threads.png and /dev/null differ diff --git a/static/diagrams/threaded-dag.png b/static/diagrams/threaded-dag.png deleted file mode 100644 index 085d0f09..00000000 Binary files a/static/diagrams/threaded-dag.png and /dev/null differ diff --git a/static/fonts/Inter-cyrillic-ext-normal-300.woff2 b/static/fonts/Inter-cyrillic-ext-normal-300.woff2 deleted file mode 100644 index 77f8fe74..00000000 Binary files a/static/fonts/Inter-cyrillic-ext-normal-300.woff2 and /dev/null differ diff --git a/static/fonts/Inter-cyrillic-ext-normal-400.woff2 b/static/fonts/Inter-cyrillic-ext-normal-400.woff2 deleted file mode 100644 index 0a28013d..00000000 Binary files a/static/fonts/Inter-cyrillic-ext-normal-400.woff2 and /dev/null differ diff --git a/static/fonts/Inter-cyrillic-ext-normal-700.woff2 b/static/fonts/Inter-cyrillic-ext-normal-700.woff2 deleted file mode 100644 index a5658ff7..00000000 Binary files a/static/fonts/Inter-cyrillic-ext-normal-700.woff2 and /dev/null differ diff --git a/static/fonts/Inter-cyrillic-ext-normal.woff2 b/static/fonts/Inter-cyrillic-ext-normal.woff2 new file mode 100644 index 00000000..2f90b7d7 Binary files /dev/null and b/static/fonts/Inter-cyrillic-ext-normal.woff2 differ diff --git a/static/fonts/Inter-cyrillic-normal-300.woff2 b/static/fonts/Inter-cyrillic-normal-300.woff2 deleted file mode 100644 index 9863e906..00000000 Binary files a/static/fonts/Inter-cyrillic-normal-300.woff2 and /dev/null differ diff --git a/static/fonts/Inter-cyrillic-normal-400.woff2 b/static/fonts/Inter-cyrillic-normal-400.woff2 deleted file mode 100644 index 9b199dff..00000000 Binary files a/static/fonts/Inter-cyrillic-normal-400.woff2 and /dev/null differ diff --git a/static/fonts/Inter-cyrillic-normal-700.woff2 b/static/fonts/Inter-cyrillic-normal-700.woff2 deleted file mode 100644 index e7c9b5c0..00000000 Binary files a/static/fonts/Inter-cyrillic-normal-700.woff2 and /dev/null differ diff --git a/static/fonts/Inter-cyrillic-normal.woff2 b/static/fonts/Inter-cyrillic-normal.woff2 new file mode 100644 index 00000000..17ec069d Binary files /dev/null and b/static/fonts/Inter-cyrillic-normal.woff2 differ diff --git a/static/fonts/Inter-greek-ext-normal-300.woff2 b/static/fonts/Inter-greek-ext-normal-300.woff2 deleted file mode 100644 index c5040704..00000000 Binary files a/static/fonts/Inter-greek-ext-normal-300.woff2 and /dev/null differ diff --git a/static/fonts/Inter-greek-ext-normal-400.woff2 b/static/fonts/Inter-greek-ext-normal-400.woff2 deleted file mode 100644 index 2133c2aa..00000000 Binary files a/static/fonts/Inter-greek-ext-normal-400.woff2 and /dev/null differ diff --git a/static/fonts/Inter-greek-ext-normal-700.woff2 b/static/fonts/Inter-greek-ext-normal-700.woff2 deleted file mode 100644 index 11f08273..00000000 Binary files a/static/fonts/Inter-greek-ext-normal-700.woff2 and /dev/null differ diff --git a/static/fonts/Inter-greek-ext-normal.woff2 b/static/fonts/Inter-greek-ext-normal.woff2 new file mode 100644 index 00000000..e6821c8e Binary files /dev/null and b/static/fonts/Inter-greek-ext-normal.woff2 differ diff --git a/static/fonts/Inter-greek-normal-300.woff2 b/static/fonts/Inter-greek-normal-300.woff2 deleted file mode 100644 index e2d53b38..00000000 Binary files a/static/fonts/Inter-greek-normal-300.woff2 and /dev/null differ diff --git a/static/fonts/Inter-greek-normal-400.woff2 b/static/fonts/Inter-greek-normal-400.woff2 deleted file mode 100644 index 3d2f76d3..00000000 Binary files a/static/fonts/Inter-greek-normal-400.woff2 and /dev/null differ diff --git a/static/fonts/Inter-greek-normal-700.woff2 b/static/fonts/Inter-greek-normal-700.woff2 deleted file mode 100644 index 5b6ed500..00000000 Binary files a/static/fonts/Inter-greek-normal-700.woff2 and /dev/null differ diff --git a/static/fonts/Inter-greek-normal.woff2 b/static/fonts/Inter-greek-normal.woff2 new file mode 100644 index 00000000..612258da Binary files /dev/null and b/static/fonts/Inter-greek-normal.woff2 differ diff --git a/static/fonts/Inter-latin-ext-normal-300.woff2 b/static/fonts/Inter-latin-ext-normal-300.woff2 deleted file mode 100644 index bf5bc647..00000000 Binary files a/static/fonts/Inter-latin-ext-normal-300.woff2 and /dev/null differ diff --git a/static/fonts/Inter-latin-ext-normal-400.woff2 b/static/fonts/Inter-latin-ext-normal-400.woff2 deleted file mode 100644 index ef110cb8..00000000 Binary files a/static/fonts/Inter-latin-ext-normal-400.woff2 and /dev/null differ diff --git a/static/fonts/Inter-latin-ext-normal-700.woff2 b/static/fonts/Inter-latin-ext-normal-700.woff2 deleted file mode 100644 index b42f8b12..00000000 Binary files a/static/fonts/Inter-latin-ext-normal-700.woff2 and /dev/null differ diff --git a/static/fonts/Inter-latin-ext-normal.woff2 b/static/fonts/Inter-latin-ext-normal.woff2 new file mode 100644 index 00000000..90ad5f74 Binary files /dev/null and b/static/fonts/Inter-latin-ext-normal.woff2 differ diff --git a/static/fonts/Inter-latin-normal-300.woff2 b/static/fonts/Inter-latin-normal-300.woff2 deleted file mode 100644 index 605d1b2d..00000000 Binary files a/static/fonts/Inter-latin-normal-300.woff2 and /dev/null differ diff --git a/static/fonts/Inter-latin-normal-400.woff2 b/static/fonts/Inter-latin-normal-400.woff2 deleted file mode 100644 index b5db4467..00000000 Binary files a/static/fonts/Inter-latin-normal-400.woff2 and /dev/null differ diff --git a/static/fonts/Inter-latin-normal-700.woff2 b/static/fonts/Inter-latin-normal-700.woff2 deleted file mode 100644 index f6215ed2..00000000 Binary files a/static/fonts/Inter-latin-normal-700.woff2 and /dev/null differ diff --git a/static/fonts/Inter-latin-normal.woff2 b/static/fonts/Inter-latin-normal.woff2 new file mode 100644 index 00000000..891fc5cc Binary files /dev/null and b/static/fonts/Inter-latin-normal.woff2 differ diff --git a/static/fonts/Inter-vietnamese-normal-300.woff2 b/static/fonts/Inter-vietnamese-normal-300.woff2 deleted file mode 100644 index 707bb805..00000000 Binary files a/static/fonts/Inter-vietnamese-normal-300.woff2 and /dev/null differ diff --git a/static/fonts/Inter-vietnamese-normal-400.woff2 b/static/fonts/Inter-vietnamese-normal-400.woff2 deleted file mode 100644 index c9fa5c59..00000000 Binary files a/static/fonts/Inter-vietnamese-normal-400.woff2 and /dev/null differ diff --git a/static/fonts/Inter-vietnamese-normal-700.woff2 b/static/fonts/Inter-vietnamese-normal-700.woff2 deleted file mode 100644 index 0dfa0850..00000000 Binary files a/static/fonts/Inter-vietnamese-normal-700.woff2 and /dev/null differ diff --git a/static/fonts/Inter-vietnamese-normal.woff2 b/static/fonts/Inter-vietnamese-normal.woff2 new file mode 100644 index 00000000..79ac1ef3 Binary files /dev/null and b/static/fonts/Inter-vietnamese-normal.woff2 differ diff --git a/static/js/toc.js b/static/js/toc.js deleted file mode 100644 index 6386e40d..00000000 --- a/static/js/toc.js +++ /dev/null @@ -1,321 +0,0 @@ -/* -Copyright 2020, 2021 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -/* -Account for id attributes that are in the sidebar nav -*/ -function populateIds() { - const navItems = document.querySelectorAll(".td-sidebar-nav li"); - return Array.from(navItems).map(item => item.id).filter(id => id != ""); -} - -/* -Given an ID and an array of IDs, return s version of the original ID that's -not equal to any of the IDs in the array. -*/ -function uniquifyHeadingId(id, uniqueIDs) { - const baseId = id; - let counter = 0; - while (uniqueIDs.includes(id)) { - counter = counter + 1; - id = baseId + "-" + counter.toString(); - } - return id; -} - -/* -Given an array of heading nodes, ensure they all have unique IDs. - -We have to do this mostly because of client-server modules, which are -rendered separately then glued together with a template. -Because heading IDs are generated in rendering, this means they can and will -end up with duplicate IDs. -*/ -function uniquifyHeadingIds(headings) { - const uniqueIDs = populateIds(); - for (let heading of headings) { - const uniqueID = uniquifyHeadingId(heading.id, uniqueIDs); - uniqueIDs.push(uniqueID); - heading.id = uniqueID; - } -} - -/* -The document contains "normal" headings, and these have corresponding items -in the ToC. - -The document might also contain H1 headings that act as titles for blocks of -rendered data, like HTTP APIs or event schemas. Unlike "normal" headings, -these headings don't appear in the ToC. But they do have anchor IDs to enable -links to them. When someone follows a link to one of these "rendered data" -headings we want to scroll the ToC to the item corresponding to the "normal" -heading preceding the "rendered data" heading we have visited. - -To support this we need to add `data` attributes to ToC items. -These attributes identify which "rendered data" headings live underneath -the heading corresponding to that ToC item. -*/ -function setTocItemChildren(toc, headings) { - let tocEntryForHeading = null; - for (const heading of headings) { - // H1 headings are rendered-data headings - if (heading.tagName !== "H1") { - tocEntryForHeading = document.querySelector(`nav li a[href="#${heading.id}"]`); - } else { - // on the ToC entry for the parent heading, - // set a data-* attribute whose name is the child's fragment ID - tocEntryForHeading.setAttribute(`data-${heading.id}`, "true"); - } - } -} - -/* -Generate a table of contents based on the headings in the document. -*/ -function makeToc() { - - // make the title from the H1 - const h1 = document.body.querySelector("h1"); - const title = document.createElement("a"); - title.id = "toc-title"; - title.setAttribute("href", "#"); - title.textContent = h1.textContent; - - // make the content - const content = document.body.querySelector(".td-content"); - let headings = [].slice.call(content.querySelectorAll("h2, h3, h4, h5, h6, .rendered-data > details > summary > h1")); - - // exclude headings that don't have IDs. - headings = headings.filter(heading => heading.id); - uniquifyHeadingIds(headings); - - // exclude .rendered-data > h1 headings from the ToC - const tocTargets = headings.filter(heading => heading.tagName !== "H1"); - - // we have to adjust heading IDs to ensure that they are unique - const nav = document.createElement("nav"); - nav.id = "TableOfContents"; - - const section = makeTocSection(tocTargets, 0); - nav.appendChild(section.content); - // build the TOC and append to it title and content - const toc = document.createElement("div"); - toc.id = "toc"; - toc.appendChild(title); - toc.appendChild(nav); - - // append TOC to the section navigation - const section_nav = document.body.querySelector("#td-section-nav"); - let hr = document.createElement("hr"); - section_nav.appendChild(hr); - section_nav.appendChild(toc); - - // tell ToC items about any rendered-data headings they contain - setTocItemChildren(section.content, headings); -} - -// create a single ToC entry -function makeTocEntry(heading) { - const li = document.createElement("li"); - const a = document.createElement("a"); - a.setAttribute("href", `#${heading.id}`); - a.textContent = heading.textContent; - li.appendChild(a); - return li; -} - -/* -Each ToC section is an `
      ` element. -ToC entries are `
    1. ` elements and these contain nested ToC sections, -whenever we go to the next heading level down. -*/ -function makeTocSection(headings, index) { - const ol = document.createElement("ol"); - let previousHeading = null; - let previousLi = null; - let i = index; - const lis = []; - for (i; i < headings.length; i++) { - const thisHeading = headings[i]; - if (previousHeading && (thisHeading.tagName > previousHeading.tagName)) { - // we are going down a heading level, create a new nested section - const section = makeTocSection(headings, i); - previousLi.appendChild(section.content); - i = section.index -1; - } - else if (previousHeading && (previousHeading.tagName > thisHeading.tagName)) { - // we have come back up a level, so a section is finished - for (let li of lis) { - ol.appendChild(li); - } - return { - content: ol, - index: i - } - } - else { - // we are still processing this section, so add this heading to the current section - previousLi = makeTocEntry(thisHeading); - lis.push(previousLi); - previousHeading = thisHeading; - } - } - for (let li of lis) { - ol.appendChild(li); - } - return { - content: ol, - index: i - } -} - -/* -Set a new ToC entry. -Clear any previously highlighted ToC items, set the new one, -and adjust the ToC scroll position. -*/ -function setTocEntry(newEntry) { - const activeEntries = document.querySelectorAll("#toc a.active"); - for (const activeEntry of activeEntries) { - activeEntry.classList.remove('active'); - } - - newEntry.classList.add('active'); - // don't scroll the sidebar nav if the main content is not scrolled - const nav = document.querySelector("#td-section-nav"); - const content = document.querySelector("html"); - if (content.scrollTop !== 0) { - nav.scrollTop = newEntry.offsetTop - 100; - } else { - nav.scrollTop = 0; - } -} - -/* -Test whether a node is in the viewport -*/ -function isInViewport(node) { - const rect = node.getBoundingClientRect(); - return ( - rect.top >= 0 && - rect.left >= 0 && - rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && - rect.right <= (window.innerWidth || document.documentElement.clientWidth) - ); -} - -/* -The callback we pass to the IntersectionObserver constructor. - -Called when any of our observed nodes starts or stops intersecting -with the viewport. -*/ -function handleIntersectionUpdate(entries) { - - /* - Special case: If the current URL hash matches a ToC entry, and - the corresponding heading is visible in the viewport, then that is - made the current ToC entry, and we don't even look at the intersection - observer data. - This means that if the user has clicked on a ToC entry, - we won't unselect it through the intersection observer. - */ - const hash = document.location.hash; - if (hash) { - let tocEntryForHash = document.querySelector(`nav li a[href="${hash}"]`); - // if the hash isn't a direct match for a ToC item, check the data attributes - if (!tocEntryForHash) { - const fragment = hash.substring(1); - tocEntryForHash = document.querySelector(`nav li a[data-${fragment}]`); - } - if (tocEntryForHash) { - const headingForHash = document.querySelector(hash); - if (headingForHash && isInViewport(headingForHash)) { - setTocEntry(tocEntryForHash); - return; - } - } - } - - let newEntry = null; - - for (const entry of entries) { - if (entry.intersectionRatio > 0) { - const heading = entry.target; - /* - This sidebar nav consists of two sections: - * at the top, a sitenav containing links to other pages - * under that, the ToC for the current page - - Since the sidebar scrolls to match the document position, - the sitenav will tend to scroll off the screen. - - If the user has scrolled up to (or near) the top of the page, - we want to show the sitenav so. - - So: if the H1 (title) for the current page has started - intersecting, then always scroll the sidebar back to the top. - */ - if (heading.tagName === "H1" && heading.parentNode.tagName === "DIV") { - const nav = document.querySelector("#td-section-nav"); - nav.scrollTop = 0; - return; - } - /* - Otherwise, get the ToC entry for the first entry that - entered the viewport, if there was one. - */ - const id = entry.target.getAttribute('id'); - let tocEntry = document.querySelector(`nav li a[href="#${id}"]`); - // if the id isn't a direct match for a ToC item, - // check the ToC entry's `data-*` attributes - if (!tocEntry) { - tocEntry = document.querySelector(`nav li a[data-${id}]`); - } - if (tocEntry && !newEntry) { - newEntry = tocEntry; - } - } - } - - if (newEntry) { - setTocEntry(newEntry); - return; - } -} - -/* -Track when headings enter the viewport, and use this to update the highlight -for the corresponding ToC entry. -*/ -window.addEventListener('DOMContentLoaded', () => { - - makeToc(); - - const toc = document.querySelector("#toc"); - toc.addEventListener("click", event => { - if (event.target.tagName === "A") { - setTocEntry(event.target); - } - }); - - const observer = new IntersectionObserver(handleIntersectionUpdate); - - document.querySelectorAll("h1, h2, h3, h4, h5, h6").forEach((section) => { - observer.observe(section); - }); - -}); diff --git a/themes/docsy b/themes/docsy deleted file mode 160000 index a0032f8d..00000000 --- a/themes/docsy +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a0032f8db919a6c67ba6cdef2c455f105b6272a2
    {{ .title }} {{ .created_at }} {{ .updated_at }}{{ with $docs_links }}{{ $docs_links }}{{ end }}{{ $authors }}{{ with $docs_links }}{{ $docs_links | safeHTML }}{{ end }}{{ $authors | safeHTML }} {{ with .shepherd }}@{{ . }}{{ end }}