Compare commits

...

43 commits
v1.16 ... main

Author SHA1 Message Date
Andrew Morgan 2f6867348f
Replace Twitter link in footer with Masto/Bluesky (#2282)
Some checks are pending
Spec / 🔎 Validate OpenAPI specifications (push) Waiting to run
Spec / 🔎 Check Event schema examples (push) Waiting to run
Spec / 🔎 Check OpenAPI definitions examples (push) Waiting to run
Spec / 🔎 Check JSON Schemas inline examples (push) Waiting to run
Spec / ⚙️ Calculate baseURL for later jobs (push) Waiting to run
Spec / 🐍 Build OpenAPI definitions (push) Blocked by required conditions
Spec / 📢 Run towncrier for changelog (push) Waiting to run
Spec / 📖 Build the spec (push) Blocked by required conditions
Spec / 🔎 Validate generated HTML (push) Blocked by required conditions
Spec / 📖 Build the historical backup spec (push) Blocked by required conditions
Spell Check / Spell Check with Typos (push) Waiting to run
2025-12-19 15:59:08 +00:00
Richard van der Hoff 6b5ff04d00 Return main to unstable status
Some checks are pending
Spec / 🔎 Validate OpenAPI specifications (push) Waiting to run
Spec / 🔎 Check Event schema examples (push) Waiting to run
Spec / 🔎 Check OpenAPI definitions examples (push) Waiting to run
Spec / 🔎 Check JSON Schemas inline examples (push) Waiting to run
Spec / ⚙️ Calculate baseURL for later jobs (push) Waiting to run
Spec / 🐍 Build OpenAPI definitions (push) Blocked by required conditions
Spec / 📢 Run towncrier for changelog (push) Waiting to run
Spec / 📖 Build the spec (push) Blocked by required conditions
Spec / 🔎 Validate generated HTML (push) Blocked by required conditions
Spec / 📖 Build the historical backup spec (push) Blocked by required conditions
Spell Check / Spell Check with Typos (push) Waiting to run
2025-12-18 16:30:28 +00:00
Richard van der Hoff ce5ae4d371 missing comma 2025-12-18 16:07:32 +00:00
Richard van der Hoff 27315feb17 Minor changelog edits 2025-12-18 15:57:59 +00:00
Richard van der Hoff a1c930d0d1 Prepare v1.17 release 2025-12-18 15:53:35 +00:00
Andrew Morgan 9e959f3922
Add a list of endpoints to the top of each spec (#2262)
Fixes #784

Add a collapsible list of endpoints to the top of the page for each distinct spec. We do this by storing endpoint metadata on $page and creating a new partial, endpoints-toc.html, which renders it.
2025-12-18 14:59:18 +00:00
Kévin Commaille 7c39427d8b
Spec device management for application services (#2267)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
As per MSC4190.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-12-17 13:13:51 +00:00
Kévin Commaille 54944e2866
Fix version selector's historical URL (#2268)
Some checks are pending
Spec / 🔎 Validate OpenAPI specifications (push) Waiting to run
Spec / 🔎 Check Event schema examples (push) Waiting to run
Spec / 🔎 Check OpenAPI definitions examples (push) Waiting to run
Spec / 🔎 Check JSON Schemas inline examples (push) Waiting to run
Spec / ⚙️ Calculate baseURL for later jobs (push) Waiting to run
Spec / 🐍 Build OpenAPI definitions (push) Blocked by required conditions
Spec / 📢 Run towncrier for changelog (push) Waiting to run
Spec / 📖 Build the spec (push) Blocked by required conditions
Spec / 🔎 Validate generated HTML (push) Blocked by required conditions
Spec / 📖 Build the historical backup spec (push) Blocked by required conditions
Spell Check / Spell Check with Typos (push) Waiting to run
* Fix version selector's historical URL

Regression because the function signature changed in #2261, but this
call was not updated.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>

* Add changelog

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>

---------

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-12-16 10:11:47 -07:00
Johannes Marbach 13aa6e83ae
Use more specific names for the version picker CSS classes and add them to the PurgeCSS safelist (#2264)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
2025-12-05 18:06:17 +00:00
Andrew Morgan 705240da72
Prevent PurgeCSS from deleting dynamically-added version picker CSS classes (#2260) 2025-12-05 15:19:24 +00:00
Johannes Marbach 4dbe080570
Append version number to 'latest' entry in the picker (#2261) 2025-12-05 14:12:05 +00:00
Johannes Marbach 7a1eb81c9c
Fix versions.json URL in unstable and local environment (#2259) 2025-12-05 12:10:18 +00:00
Johannes Marbach 22c0952003
Load versions.json as a resource if we're in the unstable spec (#2258)
Some checks are pending
Spec / 🔎 Validate OpenAPI specifications (push) Waiting to run
Spec / 🔎 Check Event schema examples (push) Waiting to run
Spec / 🔎 Check OpenAPI definitions examples (push) Waiting to run
Spec / 🔎 Check JSON Schemas inline examples (push) Waiting to run
Spec / ⚙️ Calculate baseURL for later jobs (push) Waiting to run
Spec / 🐍 Build OpenAPI definitions (push) Blocked by required conditions
Spec / 📢 Run towncrier for changelog (push) Waiting to run
Spec / 📖 Build the spec (push) Blocked by required conditions
Spec / 🔎 Validate generated HTML (push) Blocked by required conditions
Spec / 📖 Build the historical backup spec (push) Blocked by required conditions
Spell Check / Spell Check with Typos (push) Waiting to run
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
2025-12-04 11:25:07 -07:00
Johannes Marbach a5afe542c0
Add version picker in the navbar (#2256)
Some checks are pending
Spec / 🔎 Validate OpenAPI specifications (push) Waiting to run
Spec / 🔎 Check Event schema examples (push) Waiting to run
Spec / 🔎 Check OpenAPI definitions examples (push) Waiting to run
Spec / 🔎 Check JSON Schemas inline examples (push) Waiting to run
Spec / ⚙️ Calculate baseURL for later jobs (push) Waiting to run
Spec / 🐍 Build OpenAPI definitions (push) Blocked by required conditions
Spec / 📢 Run towncrier for changelog (push) Waiting to run
Spec / 📖 Build the spec (push) Blocked by required conditions
Spec / 🔎 Validate generated HTML (push) Blocked by required conditions
Spec / 📖 Build the historical backup spec (push) Blocked by required conditions
Spell Check / Spell Check with Typos (push) Waiting to run
Co-authored-by: Andrew Morgan <andrew@amorgan.xyz>
2025-12-04 12:24:28 +00:00
Johannes Marbach d28e05af87
Clarify that usage of event_id_only is not mandatory (#2255)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2025-12-01 17:41:42 +00:00
reivilibre b1fd2af72c
Clarify that servers may choose not to use M_USER_DEACTIVATED when they don't know who is asking. (#2246)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2025-11-24 17:28:16 +00:00
Forest f7a0d8d135
secrets.md: trivial grammar fix (#2250)
Co-authored-by: Andrew Morgan <andrew@amorgan.xyz>
2025-11-24 17:16:38 +00:00
Johannes Marbach a2027a3985
Spec for MSC4312: Resetting cross-signing keys in the OAuth world (#2234)
Some checks are pending
Spec / 🔎 Validate OpenAPI specifications (push) Waiting to run
Spec / 🔎 Check Event schema examples (push) Waiting to run
Spec / 🔎 Check OpenAPI definitions examples (push) Waiting to run
Spec / 🔎 Check JSON Schemas inline examples (push) Waiting to run
Spec / ⚙️ Calculate baseURL for later jobs (push) Waiting to run
Spec / 🐍 Build OpenAPI definitions (push) Blocked by required conditions
Spec / 📢 Run towncrier for changelog (push) Waiting to run
Spec / 📖 Build the spec (push) Blocked by required conditions
Spec / 🔎 Validate generated HTML (push) Blocked by required conditions
Spec / 📖 Build the historical backup spec (push) Blocked by required conditions
Spell Check / Spell Check with Typos (push) Waiting to run
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2025-11-24 10:59:32 +00:00
Hugh Nimmo-Smith ff1a39e36a
List M_RESOURCE_LIMIT_EXCEEDED under correct error code section (#2232)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2025-11-20 15:02:34 +00:00
Doug add0f2232c
Call out the possibility of redacting events that you don't have the power to send. (#2249)
Some checks are pending
Spec / 🔎 Validate OpenAPI specifications (push) Waiting to run
Spec / 🔎 Check Event schema examples (push) Waiting to run
Spec / 🔎 Check OpenAPI definitions examples (push) Waiting to run
Spec / 🔎 Check JSON Schemas inline examples (push) Waiting to run
Spec / ⚙️ Calculate baseURL for later jobs (push) Waiting to run
Spec / 🐍 Build OpenAPI definitions (push) Blocked by required conditions
Spec / 📢 Run towncrier for changelog (push) Waiting to run
Spec / 📖 Build the spec (push) Blocked by required conditions
Spec / 🔎 Validate generated HTML (push) Blocked by required conditions
Spec / 📖 Build the historical backup spec (push) Blocked by required conditions
Spell Check / Spell Check with Typos (push) Waiting to run
2025-11-20 11:22:48 +00:00
Johannes Marbach 8ebf4a4789
Clarify that device_one_time_keys_count is only optional if no unclaimed one-time keys exist (#2245)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2025-11-18 16:07:59 +00:00
Johannes Marbach 935c23485b
Clarify how to use state_after ahead of declaring full support for its spec version (#2240) 2025-11-18 10:56:22 +00:00
Johannes Marbach fe3f43a905
Point Olm and Megolm links at the new internal specification (#2242)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
Relates to: #1543
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
2025-10-31 13:52:15 +00:00
Richard van der Hoff 4783619964
Fix broken link to katex CSS (#2241)
Some checks are pending
Spec / 🔎 Validate OpenAPI specifications (push) Waiting to run
Spec / 🔎 Check Event schema examples (push) Waiting to run
Spec / 🔎 Check OpenAPI definitions examples (push) Waiting to run
Spec / 🔎 Check JSON Schemas inline examples (push) Waiting to run
Spec / ⚙️ Calculate baseURL for later jobs (push) Waiting to run
Spec / 🐍 Build OpenAPI definitions (push) Blocked by required conditions
Spec / 📢 Run towncrier for changelog (push) Waiting to run
Spec / 📖 Build the spec (push) Blocked by required conditions
Spec / 🔎 Validate generated HTML (push) Blocked by required conditions
Spec / 📖 Build the historical backup spec (push) Blocked by required conditions
Spell Check / Spell Check with Typos (push) Waiting to run
Followup to https://github.com/matrix-org/matrix-spec/pull/2226, which broke
the build. These links to the static CSS are broken in the case that the spec
is built for a subdirectory (such as `unstable`).
2025-10-31 11:02:16 +00:00
Johannes Marbach 4cafe7d9f4
Include Olm & Megolm specifications in main spec (#2226)
Fixes: #1543
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
2025-10-31 10:33:32 +00:00
Michael Telatynski e2b2e56bd2
Use NPM Trusted Publishers over token (#2239)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
* Use NPM Trusted Publishers over token

due to security changes being enacted next month by npm

* Add changelog entry

* Update npm
2025-10-29 11:44:58 -06:00
Johannes Marbach 967b54195c
Clarify the special casing of membership events and redactions in power levels (#2231) 2025-10-29 16:33:47 +00:00
Johannes Marbach 9d063c8d2d
Add m.login.terms to enumeration of authentication types (#2233)
Some checks are pending
Spec / 🔎 Validate OpenAPI specifications (push) Waiting to run
Spec / 🔎 Check Event schema examples (push) Waiting to run
Spec / 🔎 Check OpenAPI definitions examples (push) Waiting to run
Spec / 🔎 Check JSON Schemas inline examples (push) Waiting to run
Spec / ⚙️ Calculate baseURL for later jobs (push) Waiting to run
Spec / 🐍 Build OpenAPI definitions (push) Blocked by required conditions
Spec / 📢 Run towncrier for changelog (push) Waiting to run
Spec / 📖 Build the spec (push) Blocked by required conditions
Spec / 🔎 Validate generated HTML (push) Blocked by required conditions
Spec / 📖 Build the historical backup spec (push) Blocked by required conditions
Spell Check / Spell Check with Typos (push) Waiting to run
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
2025-10-28 19:05:59 -04:00
Kévin Commaille 74a0d5f289
Silence redocly-cli rule checking examples (#2238)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2025-10-24 10:19:19 +00:00
Tol Wassman 974b0b721e
fix typo (#2227)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
* fix typo

* create newsfragment

This seems to be the standard message for typo fixes.
2025-10-17 17:44:44 -04:00
Hugh Nimmo-Smith fda3be5ee3
Add note where an endpoint uses capability negotiation (#2223)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
2025-10-08 16:32:44 +01:00
Travis Ralston 7f4072d993
Spec device ID masquerading (#2221) 2025-10-08 16:52:18 +03:00
Sarthak Kumar Shailendra 58744f4734
fix: update twitter icon to x (#2219)
Some checks are pending
Spec / 🔎 Validate OpenAPI specifications (push) Waiting to run
Spec / 🔎 Check Event schema examples (push) Waiting to run
Spec / 🔎 Check OpenAPI definitions examples (push) Waiting to run
Spec / 🔎 Check JSON Schemas inline examples (push) Waiting to run
Spec / ⚙️ Calculate baseURL for later jobs (push) Waiting to run
Spec / 🐍 Build OpenAPI definitions (push) Blocked by required conditions
Spec / 📢 Run towncrier for changelog (push) Waiting to run
Spec / 📖 Build the spec (push) Blocked by required conditions
Spec / 🔎 Validate generated HTML (push) Blocked by required conditions
Spec / 📖 Build the historical backup spec (push) Blocked by required conditions
Spell Check / Spell Check with Typos (push) Waiting to run
2025-10-07 19:40:33 +01:00
Johannes Marbach dfdb1d09b8
Add missing bracket (#2224) 2025-10-07 13:18:05 -04:00
Johannes Marbach f82d8ab15b
Clarify that additional OpenGraph properties can be present in URL previews (#2225)
Some checks are pending
Spec / 🔎 Validate OpenAPI specifications (push) Waiting to run
Spec / 🔎 Check Event schema examples (push) Waiting to run
Spec / 🔎 Check OpenAPI definitions examples (push) Waiting to run
Spec / 🔎 Check JSON Schemas inline examples (push) Waiting to run
Spec / ⚙️ Calculate baseURL for later jobs (push) Waiting to run
Spec / 🐍 Build OpenAPI definitions (push) Blocked by required conditions
Spec / 📢 Run towncrier for changelog (push) Waiting to run
Spec / 📖 Build the spec (push) Blocked by required conditions
Spec / 🔎 Validate generated HTML (push) Blocked by required conditions
Spec / 📖 Build the historical backup spec (push) Blocked by required conditions
Spell Check / Spell Check with Typos (push) Waiting to run
Fixes: #1753

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
2025-10-07 10:44:20 +02:00
Travis Ralston b6a127b5cb
Clarify that restricted joins require the referenced user to be joined (#2220)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
2025-10-03 18:28:41 -06:00
Johannes Marbach 0a649cb0db
room_id is required for peeking (#2216)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
2025-10-02 12:04:11 +01:00
Johannes Marbach d8be2ad942
The server-name segment of MXC URIs is sanitised differently from the media-id segment (#2217)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
Fixes: #1990

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
2025-09-26 17:36:34 +03:00
Johannes Marbach 21109b4d5b
Push rule IDs are globally unique within their kind (#2214) 2025-09-26 11:02:36 +01:00
Johannes Marbach d4d31a8894
Don't advertise creator field in description of room creation (#2215) 2025-09-26 10:59:21 +01:00
Christian Paul d968774fb7
Missing quotation marks: Fix JSON formatting in application-service-api.md (#2213)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
2025-09-23 15:49:27 +00:00
Kévin Commaille 2aacc1feda
Remove legacy mentions (#2186)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-09-21 12:44:16 +03:00
Travis Ralston 2a8c0bc7b8 Return to unstable
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
2025-09-17 10:48:48 -06:00
88 changed files with 1927 additions and 483 deletions

View file

@ -12,6 +12,9 @@ jobs:
defaults:
run:
working-directory: packages/npm
permissions:
contents: read
id-token: write
steps:
- name: 🧮 Checkout code
uses: actions/checkout@v4
@ -23,6 +26,10 @@ jobs:
cache-dependency-path: packages/npm/yarn.lock
registry-url: "https://registry.npmjs.org"
# Ensure npm 11.5.1 or later is installed
- name: Update npm
run: npm install -g npm@latest
- name: 🔨 Install dependencies
run: "yarn install --frozen-lockfile"
@ -33,10 +40,4 @@ jobs:
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
run: npm publish --provenance --access public --tag latest

View file

@ -0,0 +1,114 @@
/*
Copyright 2025 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Determine the current version as defined in hugo.toml. This will either be
// "unstable" or "vX.X" and doesn't depend on the current URL.
//
// The oddity below is an attempt at producing a readable Hugo template while
// avoiding JS syntax errors in your IDE.
const currentVersion = `{{ if eq .Site.Params.version.status "unstable" }}
{{- /**/ -}}
unstable
{{- /**/ -}}
{{ else }}
{{- /**/ -}}
{{ printf "v%s.%s" .Site.Params.version.major .Site.Params.version.minor }}
{{- /**/ -}}
{{ end }}`;
// Determine the current version segment by regex matching the URL. This will either
// be "unstable", "latest", "vX.X" (production) or undefined (local & netlify).
const href = window.location.href;
const segmentMatches = href.match(/(?<=\/)unstable|latest|v\d+.\d+(?=\/)/);
const currentSegment = segmentMatches ? segmentMatches[0] : undefined;
// Determine the selected menu element. If we were able to obtain the version
// segment from the URL (production), use that. Otherwise (local & netlify),
// fall back to the version as defined in Hugo.
const selected = currentSegment ?? currentVersion;
function appendVersion(parent, name, segment, url) {
// The list item
const li = document.createElement("li");
if (segment === selected) {
li.classList.add("version-picker-selected");
}
if (segment === "latest") {
li.classList.add("version-picker-latest");
}
parent.appendChild(li);
// The link
const a = document.createElement("a");
a.classList.add("dropdown-item");
a.setAttribute("href", url);
li.appendChild(a);
// Handle clicks manually to preserve the current path / fragment
a.addEventListener("click", (ev) => {
// If the URL is a relative link (i.e. the historical versions changelog), just
// let the browser load it
if (url.startsWith("/")) {
return;
}
// If we couldn't determine the current segment, we cannot safely replace
// it and have to let the browser load the (root) URL instead
if (!currentSegment) {
return;
}
// Otherwise, stop further event handling and replace the segment
ev.preventDefault();
ev.stopPropagation();
window.location.href = href.replace(`/${currentSegment}/`, `/${segment}/`);
});
// The link text
const text = document.createTextNode(name);
a.appendChild(text);
}
// If we're in the unstable version, we're the latest thing and can just load
// versions.json from our own resources. Otherwise, we fall back to loading it
// from /unstable/versions.json, assuming we are on the spec.matrix.org deployment.
const url = currentVersion === "unstable"
? '{{ .Site.Home.Permalink }}versions.json'
: "/unstable/versions.json";
fetch(url)
.then(r => r.json())
.then(versions => {
// Find the surrounding list element
const ul = document.querySelector("ul#version-selector");
if (!ul) {
console.error("Cannot populate version selector: ul element not found");
return;
}
// Add a entries for the unstable version and the "latest" shortcut
appendVersion(ul, "unstable", "unstable", "https://spec.matrix.org/unstable");
const latestName = versions?.length ? `latest (${versions[0].name})` : "latest";
appendVersion(ul, latestName, "latest", "https://spec.matrix.org/latest");
// Add an entry for each proper version
for (const version of versions) {
appendVersion(ul, version.name, version.name, `https://spec.matrix.org/${version.name}`);
}
// For historical versions, simply link to the changelog
appendVersion(ul, "historical", "historical", '{{ (site.GetPage "changelog/historical").RelPermalink }}');
});

View file

@ -50,6 +50,20 @@ Custom SCSS for the Matrix spec
a {
color: $black;
}
/* Make the version dropdown scroll if it's too large */
ul#version-selector {
max-height: 80vh;
overflow-y: auto;
}
ul#version-selector li.version-picker-selected a {
font-weight: bold;
}
ul#version-selector li.version-picker-latest a {
color: $secondary;
}
}
/* Styles for the sidebar nav */
@ -243,6 +257,69 @@ Custom SCSS for the Matrix spec
}
.endpoints-toc {
summary {
cursor: pointer;
font-weight: $font-weight-bold;
font-size: 1.05rem;
margin-bottom: 0.5rem;
}
.endpoint-list {
list-style: none;
padding-left: 0;
margin: 0;
}
.endpoint-list li {
margin: 0.2rem 0;
}
.endpoint-list a {
text-decoration: none;
color: inherit;
padding: 0.05rem 0.25rem;
border-radius: 0.2rem;
&:hover {
background-color: $secondary-background;
}
}
.endpoint-list .http-api-method {
margin-right: 0.35rem;
font-weight: $font-weight-bold;
}
.endpoint-path {
font-family: $font-family-monospace;
color: $secondary;
}
.endpoint-deprecated {
color: $danger;
font-weight: $font-weight-bold;
margin-left: 0.35rem;
}
.endpoint-module {
&:not(:first-child) {
margin-top: 0.75rem;
}
}
.endpoint-module-title {
// font-weight: $font-weight-bold;
font-size: 1.20rem;
margin-bottom: 0.35rem;
}
}
.page-description {
margin-bottom: 1rem;
color: inherit;
}
/* Styles for alert boxes */
.alert {
&.note {
@ -502,6 +579,13 @@ Make padding symmetrical (this selector is used in the default styles to apply p
}
}
/* Adjust the width of math to match normal paragraphs */
@include media-breakpoint-up(lg) {
.katex-display {
max-width: 80%;
}
}
/* Adjust default styles for info banner */
.pageinfo-primary {
@include media-breakpoint-up(lg) {

View file

@ -0,0 +1 @@
Replace the Twitter link in the footer with our BlueSky and Mastodon socials.

View file

@ -43,6 +43,15 @@ description = "Home of the Matrix specification for decentralised communication"
[markup.goldmark.renderer]
# Enables us to render raw HTML
unsafe = true
[markup.goldmark.extensions]
# Tell Goldmark to pass delimited blocks through the `render-passthrough` render hook.
# This is used to render the maths in the Olm spec.
# See: https://gohugo.io/functions/transform/tomath/#step-1.
[markup.goldmark.extensions.passthrough]
enable = true
[markup.goldmark.extensions.passthrough.delimiters]
block = [['\[', '\]']]
inline = [['\(', '\)']]
[markup.highlight]
# See a complete list of available styles at https://xyproto.github.io/splash/docs/all.html
# If the style is changed, remember to regenerate the CSS with:
@ -61,13 +70,17 @@ copyright = "The Matrix.org Foundation CIC"
[params.version]
# must be one of "unstable", "current", "historical"
# this is used to decide whether to show a banner pointing to the current release
status = "stable"
status = "unstable"
# A URL pointing to the latest, stable release of the spec. To be shown in the unstable version warning banner.
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.
major = "1"
minor = "16"
#major = "1"
#minor = "17"
[[params.versions]]
# We must include this parameter to enable docsy's version picker in the navbar. The picker
# is populated automatically in navbar-version-selector.html.
# User interface configuration
[params.ui]
@ -93,25 +106,30 @@ sidebar_menu_compact = true
# 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"
name = "GitHub"
url = "https://github.com/matrix-org"
icon = "fab fa-github"
desc = "Matrix on GitHub"
[[params.links.bottom]]
name = "GitLab"
url = "https://gitlab.matrix.org/matrix-org"
icon = "fab fa-gitlab"
name = "GitLab"
url = "https://gitlab.matrix.org/matrix-org"
icon = "fab fa-gitlab"
desc = "Matrix on GitLab"
[[params.links.bottom]]
name = "YouTube"
url = "https://www.youtube.com/channel/UCVFkW-chclhuyYRbmmfwt6w"
icon = "fab fa-youtube"
name = "YouTube"
url = "https://www.youtube.com/channel/UCVFkW-chclhuyYRbmmfwt6w"
icon = "fab fa-youtube"
desc = "Matrix YouTube channel"
[[params.links.bottom]]
name = "Twitter"
url = "https://twitter.com/matrixdotorg"
icon = "fab fa-twitter"
desc = "Matrix on Twitter"
name = "Mastodon"
url = "https://mastodon.matrix.org/@matrix"
icon = "fab fa-mastodon"
desc = "Matrix on Mastodon"
[[params.links.bottom]]
name = "Bluesky"
url = "https://bsky.app/profile/matrix.org"
icon = "fab fa-bluesky"
desc = "Matrix on Bluesky"
# configuration for the hugo development server
@ -121,7 +139,9 @@ sidebar_menu_compact = true
[[server.headers]]
for = '/**'
[server.headers.values]
Content-Security-Policy = "default-src 'self'; style-src 'self'; script-src 'self'; img-src 'self' data:; connect-src 'self'; font-src 'self' data:; media-src 'self'; child-src 'self'; form-action 'self'; object-src 'self'"
# `style-src 'unsafe-inline'` is needed to correctly render the maths in the Olm spec:
# https://github.com/KaTeX/KaTeX/issues/4096
Content-Security-Policy = "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self'; img-src 'self' data:; connect-src 'self'; font-src 'self' data:; media-src 'self'; child-src 'self'; form-action 'self'; object-src 'self'"
X-XSS-Protection = "1; mode=block"
X-Content-Type-Options = "nosniff"
# Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload"

View file

@ -25,6 +25,7 @@ The specification consists of the following parts:
* [Identity Service API](/identity-service-api)
* [Push Gateway API](/push-gateway-api)
* [Room Versions](/rooms)
* [Olm & Megolm](/olm-megolm)
* [Appendices](/appendices)
Additionally, this introduction page contains the key baseline
@ -151,7 +152,7 @@ request.
How data flows between clients:
```
```nohighlight
{ Matrix client A } { Matrix client B }
^ | ^ |
| events | Client-Server API | events |

View file

@ -749,13 +749,13 @@ history (a permalink).
The Matrix URI scheme is defined as follows (`[]` enclose optional parts, `{}`
enclose variables):
```
```nohighlight
matrix:[//{authority}/]{type}/{id without sigil}[/{type}/{id without sigil}...][?{query}][#{fragment}]
```
As a schema, this can be represented as:
```
```nohighlight
MatrixURI = "matrix:" hier-part [ "?" query ] [ "#" fragment ]
hier-part = [ "//" authority "/" ] path
path = entity-descriptor ["/" entity-descriptor]
@ -865,7 +865,7 @@ below for more details.
A matrix.to URI has the following format, based upon the specification
defined in [RFC 3986](https://tools.ietf.org/html/rfc3986):
```
```nohighlight
https://matrix.to/#/<identifier>/<extra parameter>?<additional arguments>
```

View file

@ -2,16 +2,14 @@
title: "Application Service API"
weight: 30
type: docs
description: |
The Matrix client-server API and server-server APIs provide a consistent,
self-contained federated messaging fabric but leave little room for custom
server-side behaviour such as gateways, filters, or extensible hooks. The
Application Service API defines a standard way to add this extensible
functionality, independent of the underlying homeserver implementation.
---
The Matrix client-server API and server-server APIs provide the means to
implement a consistent self-contained federated messaging fabric.
However, they provide limited means of implementing custom server-side
behaviour in Matrix (e.g. gateways, filters, extensible hooks etc). The
Application Service API (AS API) defines a standard API to allow such
extensible functionality to be implemented irrespective of the
underlying homeserver implementation.
## Application Services
Application services are passive and can only observe events from the
@ -178,13 +176,13 @@ The application service API provides a transaction API for sending a
list of events. Each list of events includes a transaction ID, which
works as follows:
```
```nohighlight
Typical
HS ---> AS : Homeserver sends events with transaction ID T.
<--- : Application Service sends back 200 OK.
```
```
```nohighlight
AS ACK Lost
HS ---> AS : Homeserver sends events with transaction ID T.
<-/- : AS 200 OK is lost.
@ -258,7 +256,7 @@ have been omitted for brevity):
**Typical**
```
```nohighlight
AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"}
HS ---> AS : /_matrix/app/v1/ping {"transaction_id": "meow"}
HS <--- AS : 200 OK {}
@ -267,7 +265,7 @@ AS <--- HS : 200 OK {"duration_ms": 123}
**Incorrect `hs_token`**
```
```nohighlight
AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"}
HS ---> AS : /_matrix/app/v1/ping {"transaction_id": "meow"}
HS <--- AS : 403 Forbidden {"errcode": "M_FORBIDDEN"}
@ -276,7 +274,7 @@ AS <--- HS : 502 Bad Gateway {"errcode": "M_BAD_STATUS", "status": 403, "body":
**Can't connect to appservice**
```
```nohighlight
AS ---> HS : /_matrix/client/v1/appservice/{appserviceId}/ping {"transaction_id": "meow"}
HS -/-> AS : /_matrix/app/v1/ping {"transaction_id": "meow"}
AS <--- HS : 502 Bad Gateway {"errcode": "M_CONNECTION_FAILED"}
@ -356,6 +354,7 @@ service would like to masquerade as.
Inputs:
- Application service token (`as_token`)
- User ID in the AS namespace to act as.
- Device ID belonging to the User ID to act with.
Notes:
- This applies to all aspects of the Client-Server API, except for
@ -375,9 +374,19 @@ service's `user` namespaces. If the parameter is missing, the homeserver
is to assume the application service intends to act as the user implied
by the `sender_localpart` property of the registration.
{{% added-in v="1.17" %}} Application services MAY similarly masquerade
as a specific device ID belonging the user ID through use of the `device_id`
query string parameter on the request. If the given device ID is not known
to belong to the user, the server will return a 400 `M_UNKNOWN_DEVICE` error.
If no `user_id` is supplied, the `device_id` MUST belong to the user implied
by the `sender_localpart` property of the application service's registration.
If no `device_id` is supplied, the homeserver is to assume the request is
being made without a device ID and will fail to complete operations which
require a device ID (such as uploading one-time keys).
An example request would be:
GET /_matrix/client/v3/account/whoami?user_id=@_irc_user:example.org
GET /_matrix/client/v3/account/whoami?user_id=@_irc_user:example.org&device_id=ABC123
Authorization: Bearer YourApplicationServiceTokenHere
#### Timestamp massaging
@ -417,6 +426,8 @@ imports and similar behaviour).
#### Server admin style permissions
{{% changed-in v="1.17" %}}
The homeserver needs to give the application service *full control* over
its namespace, both for users and for room aliases. This means that the
AS should be able to manage any users and room alias in its namespace. No additional API
@ -433,33 +444,59 @@ achieved by including the `as_token` on a `/register` request, along
with a login type of `m.login.application_service` to set the desired
user ID without a password.
POST /_matrix/client/v3/register
Authorization: Bearer YourApplicationServiceTokenHere
```http
POST /_matrix/client/v3/register
Authorization: Bearer YourApplicationServiceTokenHere
```
Content:
{
type: "m.login.application_service",
username: "_irc_example"
}
```json
{
"type": "m.login.application_service",
"username": "_irc_example"
}
```
Similarly, logging in as users needs API changes in order to allow the AS to
log in without needing the user's password. This is achieved by including the
`as_token` on a `/login` request, along with a login type of
`m.login.application_service`:
{{% boxes/note %}}
{{% added-in v="1.17" %}}
Servers MUST still allow application services to use the `/register` endpoint
with a login type of `m.login.application_service` even if they don't support
the [Legacy Authentication API](/client-server-api/#legacy-api).
In that case application services MUST set the `"inhibit_login": true` parameter
as they cannot use it to log in as users. If the `inhibit_login` parameter is
not set to `true`, the server MUST return a 400 HTTP status code with an
`M_APPSERVICE_LOGIN_UNSUPPORTED` error code.
{{% /boxes/note %}}
Similarly, logging in as users using the [Legacy authentication API](/client-server-api/#legacy-api)
needs API changes in order to allow the AS to log in without needing the user's
password. This is achieved by including the `as_token` on a `/login` request,
along with a login type of `m.login.application_service`:
{{% added-in v="1.2" %}}
POST /_matrix/client/v3/login
Authorization: Bearer YourApplicationServiceTokenHere
```http
POST /_matrix/client/v3/login
Authorization: Bearer YourApplicationServiceTokenHere
```
Content:
{
type: "m.login.application_service",
"identifier": {
"type": "m.id.user",
"user": "_irc_example"
}
}
```json
{
"type": "m.login.application_service",
"identifier": {
"type": "m.id.user",
"user": "_irc_example"
}
}
```
{{% boxes/note %}}
{{% added-in v="1.17" %}}
Application services MUST NOT use the `/login` endpoint if the server doesn't
support the Legacy authentication API. If `/login` is called with the
`m.login.application_service` login type the server MUST return a 400 HTTP
status code with an `M_APPSERVICE_LOGIN_UNSUPPORTED` error code.
{{% /boxes/note %}}
Application services which attempt to create users or aliases *outside*
of their defined namespaces, or log in as users outside of their defined
@ -501,6 +538,38 @@ client-server endpoint.
{{% http-api spec="client-server" api="appservice_room_directory" %}}
#### Device management
{{% added-in v="1.17" %}}
Application services need to be able to create and delete devices to manage the
encryption for their users without having to rely on `/login`, which also
generates an access token for the user, and which might not be available for
homeservers that only support the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
##### Creating devices
Application services can use the [`PUT /_matrix/client/v3/devices/{deviceId}`](/client-server-api/#put_matrixclientv3devicesdeviceid)
endpoint to create new devices.
##### Deleting devices
The following endpoints used to delete devices MUST NOT require [User-Interactive
Authentication](/client-server-api/#user-interactive-authentication-api) when
used by an application service:
* [`DELETE /_matrix/client/v3/devices/{deviceId}`](/client-server-api/#delete_matrixclientv3devicesdeviceid)
* [`POST /_matrix/client/v3/delete_devices`](/client-server-api/#post_matrixclientv3delete_devices)
#### Cross-signing
{{% added-in v="1.17" %}}
Appservices need to be able to verify themselves and replace their cross-signing
keys, so the [`POST /_matrix/client/v3/keys/device_signing/upload`](/client-server-api/#post_matrixclientv3keysdevice_signingupload)
endpoint MUST NOT require [User-Interactive Authentication](/client-server-api/#user-interactive-authentication-api)
when used by an application service, even if cross-signing keys already exist.
### Referencing messages from a third-party network
Application services should include an `external_url` in the `content`

View file

@ -0,0 +1,91 @@
---
title: v1.17 Changelog
linkTitle: v1.17
type: docs
layout: changelog
outputs:
- html
- checklist
date: 2025-12-18
---
## Client-Server API
**Removed Endpoints**
- Remove legacy mentions, as per [MSC4210](https://github.com/matrix-org/matrix-spec-proposals/issues/4210). ([#2186](https://github.com/matrix-org/matrix-spec/issues/2186))
**Backwards Compatible Changes**
- Allow application services to masquerade as specific devices belonging to users, as per [MSC4326](https://github.com/matrix-org/matrix-spec-proposals/pull/4326). ([#2221](https://github.com/matrix-org/matrix-spec/issues/2221))
- Add the `m.oauth` authentication type for User-Interactive Authentication, as per [MSC4312](https://github.com/matrix-org/matrix-spec-proposals/pull/4312). ([#2234](https://github.com/matrix-org/matrix-spec/issues/2234))
- Allow application services to manage devices and register users without the legacy authentication API, as per [MSC4190](https://github.com/matrix-org/matrix-spec-proposals/pull/4190). ([#2267](https://github.com/matrix-org/matrix-spec/issues/2267))
**Spec Clarifications**
- Push rule IDs are globally unique within their kind. ([#2214](https://github.com/matrix-org/matrix-spec/issues/2214))
- Don't advertise `creator` field in description of room creation. ([#2215](https://github.com/matrix-org/matrix-spec/issues/2215))
- `room_id` is required for peeking via `/_matrix/client/v3/events`. ([#2216](https://github.com/matrix-org/matrix-spec/issues/2216))
- The `server-name` segment of MXC URIs is sanitised differently from the `media-id` segment. ([#2217](https://github.com/matrix-org/matrix-spec/issues/2217))
- Add note to each endpoint that uses capability negotiation. ([#2223](https://github.com/matrix-org/matrix-spec/issues/2223))
- Additional OpenGraph properties can be present in URL previews. ([#2225](https://github.com/matrix-org/matrix-spec/issues/2225))
- Clarify the special casing of membership events and redactions in power levels. ([#2231](https://github.com/matrix-org/matrix-spec/issues/2231))
- `M_RESOURCE_LIMIT_EXCEEDED` is now listed as a common error code. ([#2232](https://github.com/matrix-org/matrix-spec/issues/2232))
- Add `m.login.terms` to enumeration of authentication types. ([#2233](https://github.com/matrix-org/matrix-spec/issues/2233))
- Clarify how to use `state_after` ahead of declaring full support for its spec version. ([#2240](https://github.com/matrix-org/matrix-spec/issues/2240))
- `device_one_time_keys_count` is only optional if no unclaimed one-time keys exist. ([#2245](https://github.com/matrix-org/matrix-spec/issues/2245))
- Clarify that servers may choose not to use `M_USER_DEACTIVATED` at login time, for example for privacy reasons when they can't authenticate deactivated users. ([#2246](https://github.com/matrix-org/matrix-spec/issues/2246))
- Usage of the `event_id_only` format for push notifications is not mandatory. ([#2255](https://github.com/matrix-org/matrix-spec/issues/2255))
- Fix various typos throughout the specification. ([#2224](https://github.com/matrix-org/matrix-spec/issues/2224), [#2227](https://github.com/matrix-org/matrix-spec/issues/2227), [#2250](https://github.com/matrix-org/matrix-spec/issues/2250))
## Server-Server API
No significant changes.
## Application Service API
**Backwards Compatible Changes**
- Allow application services to masquerade as specific devices belonging to users, as per [MSC4326](https://github.com/matrix-org/matrix-spec-proposals/pull/4326). ([#2221](https://github.com/matrix-org/matrix-spec/issues/2221))
- Allow application services to manage devices and register users without the legacy authentication API, as per [MSC4190](https://github.com/matrix-org/matrix-spec-proposals/pull/4190). ([#2267](https://github.com/matrix-org/matrix-spec/issues/2267))
**Spec Clarifications**
- Fix JSON formatting in the "Server admin style permissions" examples. ([#2213](https://github.com/matrix-org/matrix-spec/issues/2213))
## Identity Service API
No significant changes.
## Push Gateway API
No significant changes.
## Room Versions
**Spec Clarifications**
- In room versions 8 through 12, clarify that "sufficient permission to invite users" on restricted joins also includes being a joined member of the room. ([#2220](https://github.com/matrix-org/matrix-spec/issues/2220))
- In room versions 3 through 12, clarify that when you have the power to redact, it is possible to redact events that you don't have the power to send. ([#2249](https://github.com/matrix-org/matrix-spec/issues/2249))
## Appendices
No significant changes.
## Internal Changes/Tooling
**Spec Clarifications**
- Swapped icon for X (fka. twitter) to updated logo in footer. ([#2219](https://github.com/matrix-org/matrix-spec/issues/2219))
- Inline Olm & Megolm specifications. ([#2226](https://github.com/matrix-org/matrix-spec/issues/2226), [#2241](https://github.com/matrix-org/matrix-spec/issues/2241), [#2242](https://github.com/matrix-org/matrix-spec/issues/2242))
- Silence failing redocly-cli rule. ([#2238](https://github.com/matrix-org/matrix-spec/issues/2238))
- Use NPM Trusted Publishers for publishing `@matrix-org/spec` to npm. ([#2239](https://github.com/matrix-org/matrix-spec/issues/2239))
- Add version picker in the navbar. ([#2256](https://github.com/matrix-org/matrix-spec/issues/2256), [#2258](https://github.com/matrix-org/matrix-spec/issues/2258), [#2259](https://github.com/matrix-org/matrix-spec/issues/2259), [#2260](https://github.com/matrix-org/matrix-spec/issues/2260), [#2261](https://github.com/matrix-org/matrix-spec/issues/2261), [#2264](https://github.com/matrix-org/matrix-spec/issues/2264), [#2268](https://github.com/matrix-org/matrix-spec/issues/2268))
- Add a list of endpoints to the top of each spec page. ([#2262](https://github.com/matrix-org/matrix-spec/issues/2262))

View file

@ -2,14 +2,14 @@
title: "Client-Server API"
weight: 10
type: docs
description: |
The client-server API allows clients to send messages, control rooms and
synchronise conversation history. It is designed to support both lightweight
clients which store no state and lazy-load data from the server as required,
as well as heavyweight clients which maintain a full local persistent copy of
server state.
---
The client-server API allows clients to
send messages, control rooms and synchronise conversation history. It is
designed to support both lightweight clients which store no state and
lazy-load data from the server as required - as well as heavyweight
clients which maintain a full local persistent copy of server state.
## API Standards
{{% boxes/note %}}
@ -132,6 +132,21 @@ The server did not understand the request. This is expected to be returned with
a 404 HTTP status code if the endpoint is not implemented or a 405 HTTP status
code if the endpoint is implemented, but the incorrect HTTP method is used.
`M_UNKNOWN_DEVICE`
{{% added-in v="1.17" %}} The device ID supplied by the application service does
not belong to the user ID during [identity assertion](/application-service-api/#identity-assertion).
`M_RESOURCE_LIMIT_EXCEEDED`
The request cannot be completed because the homeserver has reached a
resource limit imposed on it. For example, a homeserver held in a shared
hosting environment may reach a resource limit if it starts using too
much memory or disk space. The error MUST have an `admin_contact` field
to provide the user receiving the error a place to reach out to.
Typically, this error will appear on routes which attempt to modify
state (e.g.: sending messages, account data, etc) and not routes which
only read state (e.g.: [`/sync`](#get_matrixclientv3sync),
[`/user/{userId}/account_data/{type}`](#get_matrixclientv3useruseridaccount_datatype), etc).
`M_UNKNOWN`
An unknown error has occurred.
@ -217,17 +232,6 @@ The request or entity was too large.
The resource being requested is reserved by an application service, or
the application service making the request has not created the resource.
`M_RESOURCE_LIMIT_EXCEEDED`
The request cannot be completed because the homeserver has reached a
resource limit imposed on it. For example, a homeserver held in a shared
hosting environment may reach a resource limit if it starts using too
much memory or disk space. The error MUST have an `admin_contact` field
to provide the user receiving the error a place to reach out to.
Typically, this error will appear on routes which attempt to modify
state (e.g.: sending messages, account data, etc) and not routes which
only read state (e.g.: [`/sync`](#get_matrixclientv3sync),
[`/user/{userId}/account_data/{type}`](#get_matrixclientv3useruseridaccount_datatype), etc).
`M_CANNOT_LEAVE_SERVER_NOTICE_ROOM`
The user is unable to reject an invite to join the server notices room.
See the [Server Notices](#server-notices) module for more information.
@ -473,8 +477,7 @@ the API that was used to obtain their current access token.
{{% boxes/note %}}
Currently the OAuth 2.0 API doesn't cover all the use cases of the legacy API,
such as automated applications that cannot use a web browser, or
user management by [application services](application-service-api/#server-admin-style-permissions).
such as automated applications that cannot use a web browser.
{{% /boxes/note %}}
### Authentication API discovery
@ -498,6 +501,12 @@ user must do that directly in the homeserver's web UI. However, the client can
signal to the homeserver that the user wishes to create a new account with the
[`prompt=create`](#user-registration) parameter during authorization.
{{% boxes/note %}}
{{% added-in v="1.17" %}}
Application services can use the `/register` endpoint to create users regardless
of the authentication API supported by the homeserver.
{{% /boxes/note %}}
### Login
With the legacy API, a client can obtain an access token by using one of the
@ -683,7 +692,7 @@ request parameter.
A client should first make a request with no `auth` parameter.
The homeserver returns an HTTP 401 response, with a JSON body, as follows:
```
```nohighlight
HTTP/1.1 401 Unauthorized
Content-Type: application/json
```
@ -729,7 +738,7 @@ given. It also contains other keys dependent on the auth type being
attempted. For example, if the client is attempting to complete auth
type `example.type.foo`, it might submit something like this:
```
```nohighlight
POST /_matrix/client/v3/endpoint HTTP/1.1
Content-Type: application/json
```
@ -752,7 +761,7 @@ along with the same object as when no authentication was attempted, with
the addition of the `completed` key which is an array of auth types the
client has completed successfully:
```
```nohighlight
HTTP/1.1 401 Unauthorized
Content-Type: application/json
```
@ -786,7 +795,7 @@ but the client may make a second attempt, it returns the same HTTP
status 401 response as above, with the addition of the standard
`errcode` and `error` fields describing the error. For example:
```
```nohighlight
HTTP/1.1 401 Unauthorized
Content-Type: application/json
```
@ -816,7 +825,7 @@ Content-Type: application/json
If the request fails for a reason other than authentication, the server
returns an error message in the standard format. For example:
```
```nohighlight
HTTP/1.1 400 Bad request
Content-Type: application/json
```
@ -855,7 +864,7 @@ must still give a 401 response to requests with no auth data.
At a high level, the requests made for an API call completing an auth
flow with three stages will resemble the following diagram:
```
```nohighlight
_______________________
| Stage 0 |
| No auth |
@ -902,6 +911,8 @@ This specification defines the following auth types:
- `m.login.msisdn`
- `m.login.dummy`
- `m.login.registration_token`
- {{% added-in v="1.11" %}} `m.login.terms`
- {{% added-in v="1.17" %}} `m.oauth`
###### Password-based
@ -913,7 +924,7 @@ This specification defines the following auth types:
To use this authentication type, clients should submit an auth dict as
follows:
```
```nohighlight
{
"type": "m.login.password",
"identifier": {
@ -1163,7 +1174,7 @@ user during registration, if applicable.
1. A client might submit a registration request as follows:
```
```nohighlight
POST /_matrix/client/v3/register
```
```json
@ -1176,7 +1187,7 @@ user during registration, if applicable.
2. The server requires the user to accept some terms of service before
registration, so returns the following response:
```
```nohighlight
HTTP/1.1 401 Unauthorized
Content-Type: application/json
```
@ -1211,7 +1222,7 @@ user during registration, if applicable.
4. The client repeats the registration request, confirming that the user has
accepted the documents:
```
```nohighlight
POST /_matrix/client/v3/register
```
```json
@ -1226,7 +1237,7 @@ user during registration, if applicable.
```
5. All authentication steps have now completed, so the request is successful:
```
```nohighlight
HTTP/1.1 200 OK
Content-Type: application/json
```
@ -1240,6 +1251,40 @@ user during registration, if applicable.
{{% definition path="api/client-server/definitions/m.login.terms_params" %}}
###### OAuth authentication
{{% added-in v="1.17" %}}
| Type | Description |
|-------------------------------|-------------------------------------------------------------------|
| `m.oauth` | Authentication is supported by authorising via the homeserver's OAuth account management web UI. |
{{% boxes/note %}}
The `m.oauth` authentication type is currently only valid on the
[`/keys/device_signing/upload`](/client-server-api/#post_matrixclientv3keysdevice_signingupload) endpoint.
{{% /boxes/note %}}
This authentication type provides homeservers the ability to guard access to
sensitive actions when the client has authenticated via the
[OAuth 2.0 API](/client-server-api/#oauth-20-api), which is otherwise not
compatible with User-Interactive Authentication (UIA). To do so, the server
returns a 401 response on the respective request, where the response body
includes `m.oauth` in the `flows` list, and the `m.oauth` property in the
`params` object has the structure [shown below](#definition-moauth-params).
The client is expected to open the contained URL to let the user confirm the
action in the homeserver's account management web UI. Once the user has done
so, the client submits an `auth` dict with just the `session`, as follows,
to complete the stage:
```json
{
"session": "<session ID>"
}
```
{{% definition path="api/client-server/definitions/m.oauth_params" %}}
##### Fallback
Clients cannot be expected to be able to know how to process every
@ -1522,6 +1567,10 @@ If the access token does correspond to an appservice, but the user id does
not lie within its namespace then the homeserver will respond with an
errcode of `M_EXCLUSIVE`.
{{% added-in v="1.17" %}} If this login type is used and the server doesn't
support logging in via the Legacy authentication API, it MUST return a 400 HTTP
status code with an `M_APPSERVICE_LOGIN_UNSUPPORTED` error code.
##### Login Fallback
If a client does not recognize any or all login flows it can use the
@ -1586,6 +1635,11 @@ because they don't have access to the user's credentials anymore.
The [User-Interactive Authentication API](#user-interactive-authentication-api)
is not compatible with the OAuth 2.0 API, so the endpoints that depend on it for
authentication can't be used when an access token is obtained with this API.
The only exception to this is the
[`/keys/device_signing/upload`](/client-server-api/#post_matrixclientv3keysdevice_signingupload)
endpoint which uses the [`m.oauth`](/client-server-api/#oauth-authentication)
authentication type.
{{% /boxes/warning %}}
**Sample flow**
@ -1647,7 +1701,7 @@ This authorization request URL must be opened in the user's browser:
Sample authorization request, with extra whitespaces for readability:
```
```nohighlight
https://account.example.com/oauth2/auth?
client_id = s6BhdRkqt3 &
response_type = code &
@ -1680,7 +1734,7 @@ used in the authorization request.
A successful authorization will have a `code` value, for example:
```
```nohighlight
https://app.example.com/oauth2-callback#state=ewubooN9weezeewah9fol4oothohroh3&code=iuB7Eiz9heengah1joh2ioy9ahChuP6R
```
@ -1692,7 +1746,7 @@ A failed authorization will have the following values:
For example:
```
```nohighlight
https://app.example.com/oauth2-callback#state=ewubooN9weezeewah9fol4oothohroh3&error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request.&error_uri=https%3A%2F%2Ferrors.example.com%2F
```
@ -1717,7 +1771,7 @@ type, the expiration time, and the refresh token.
Sample token request:
```
```nohighlight
POST /oauth2/token HTTP/1.1
Host: account.example.com
Content-Type: application/x-www-form-urlencoded
@ -2040,7 +2094,7 @@ When generating a new `device_id`, the client SHOULD generate a random string
with enough entropy. It SHOULD only use characters from the unreserved character
list defined by [RFC 3986 section 2.3](https://datatracker.ietf.org/doc/html/rfc3986#section-2.3):
```
```nohighlight
unreserved = a-z / A-Z / 0-9 / "-" / "." / "_" / "~"
```
@ -2053,7 +2107,7 @@ In any case it MUST only use characters allowed by the OAuth 2.0 scope
definition in [RFC 6749 section 3.3](https://datatracker.ietf.org/doc/html/rfc6749#section-3.3),
which is defined as the following ASCII ranges:
```
```nohighlight
%x21 / %x23-5B / %x5D-7E
```
@ -2195,7 +2249,7 @@ The body of the request includes the following parameters, encoded as
For example, revoking using the access token:
```
```nohighlight
POST /oauth2/revoke HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
@ -2240,7 +2294,7 @@ set to `true` on all but the following Client-Server APIs:
Servers MAY additionally include details of why the lock was applied in
the `error` field.
```
```nohighlight
HTTP/1.1 401 Unauthorized
Content-Type: application/json
```
@ -2320,7 +2374,7 @@ When a client attempts to perform an action while suspended, the server MUST
respond with a `403 Forbidden` error response with `M_USER_SUSPENDED` as the
error code, as shown below:
```
```nohighlight
HTTP/1.1 403 Forbidden
Content-Type: application/json
```
@ -2928,7 +2982,7 @@ For example, a `/sync` request might return a range of four events
`E2`, `E3`, `E4` and `E5` within a given room, omitting two prior events
`E0` and `E1`. This can be visualised as follows:
```
```nohighlight
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]
^ ^
| |
@ -2946,7 +3000,7 @@ deprecated `/events` API) support long-polling in this way.
Continuing the example above, an incremental sync might report
a single new event `E6`. The response can be visualised as:
```
```nohighlight
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]
^ ^
| |
@ -2970,7 +3024,7 @@ the `since` parameter. The server knows about four new events, `E7`, `E8`,
the server sends a `limited` response containing `E8`, `E9` and `E10`but
omitting `E7`. This forms a gap, which we can see in the visualisation:
```
```nohighlight
| gap |
| <-> |
[E0]->[E1]->[E2]->[E3]->[E4]->[E5]->[E6]->[E7]->[E8]->[E9]->[E10]
@ -3065,29 +3119,29 @@ to another.
Valid requests look like:
```
```nohighlight
PUT /rooms/!roomid:domain/state/m.example.event
{ "key" : "without a state key" }
```
```
```nohighlight
PUT /rooms/!roomid:domain/state/m.another.example.event/foo
{ "key" : "with 'foo' as the state key" }
```
In contrast, these requests are invalid:
```
```nohighlight
POST /rooms/!roomid:domain/state/m.example.event/
{ "key" : "cannot use POST here" }
```
```
```nohighlight
PUT /rooms/!roomid:domain/state/m.another.example.event/foo/11
{ "key" : "txnIds are not supported" }
```
Care should be taken to avoid setting the wrong `state key`:
```
```nohighlight
PUT /rooms/!roomid:domain/state/m.another.example.event/11
{ "key" : "with '11' as the state key, but was probably intended to be a txnId" }
```
@ -3095,7 +3149,7 @@ PUT /rooms/!roomid:domain/state/m.another.example.event/11
The `state_key` is often used to store state about individual users, by
using the user ID as the `state_key` value. For example:
```
```nohighlight
PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Aexample.org
{ "animal" : "cat", "reason": "fluffy" }
```
@ -3103,7 +3157,7 @@ PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Aexample.org
In some cases, there may be no need for a `state_key`, so it can be
omitted:
```
```nohighlight
PUT /rooms/!roomid:domain/state/m.room.bgd.color
{ "color": "red", "hex": "#ff0000" }
```
@ -3386,10 +3440,10 @@ Unspecified room types are permitted through the use of
### Creation
The homeserver will create an `m.room.create` event when a room is
created, which serves as the root of the event graph for this room. This
event also has a `creator` key which contains the user ID of the room
creator. It will also generate several other events in order to manage
permissions in this room. This includes:
created, which serves as the root of the event graph for this room. The
event `sender` is the user ID of the room creator. The server will also
generate several other events in order to manage permissions in this room.
This includes:
- `m.room.power_levels` : Sets the power levels of users and required power
levels for various actions within the room such as sending events.
@ -3908,42 +3962,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" filename="instant_messaging" %}}
{{% cs-module name="Rich replies" filename="rich_replies" %}}
{{% cs-module name="Voice over IP" filename="voip_events" %}}
{{% cs-module name="Typing Notifications" filename="typing_notifications" %}}
{{% cs-module name="Receipts" filename="receipts" %}}
{{% cs-module name="Read and unread markers" filename="read_markers" %}}
{{% cs-module name="Presence" filename="presence" %}}
{{% cs-module name="Content repository" filename="content_repo" %}}
{{% cs-module name="Send-to-Device messaging" filename="send_to_device" %}}
{{% cs-module name="Device Management" filename="device_management" %}}
{{% cs-module name="End-to-End Encryption" filename="end_to_end_encryption" %}}
{{% cs-module name="Secrets" filename="secrets" %}}
{{% cs-module name="Room History Visibility" filename="history_visibility" %}}
{{% cs-module name="Push Notifications" filename="push" %}}
{{% cs-module name="Third-party invites" filename="third_party_invites" %}}
{{% cs-module name="Server Side Search" filename="search" %}}
{{% cs-module name="Guest Access" filename="guest_access" %}}
{{% cs-module name="Room Previews" filename="room_previews" %}}
{{% cs-module name="Room Tagging" filename="tags" %}}
{{% cs-module name="Client Config" filename="account_data" %}}
{{% cs-module name="Server Administration" filename="admin" %}}
{{% cs-module name="Event Context" filename="event_context" %}}
{{% cs-module name="SSO client login/authentication" filename="sso_login" %}}
{{% cs-module name="Direct Messaging" filename="dm" %}}
{{% cs-module name="Ignoring Users" filename="ignore_users" %}}
{{% cs-module name="Sticker Messages" filename="stickers" %}}
{{% cs-module name="Reporting Content" filename="report_content" %}}
{{% cs-module name="Third-party Networks" filename="third_party_networks" %}}
{{% cs-module name="OpenID" filename="openid" %}}
{{% cs-module name="Server Access Control Lists (ACLs) for rooms" filename="server_acls" %}}
{{% cs-module name="User and room mentions" filename="mentions" %}}
{{% cs-module name="Room Upgrades" filename="room_upgrades" %}}
{{% cs-module name="Server Notices" filename="server_notices" %}}
{{% cs-module name="Moderation policy lists" filename="moderation_policies" %}}
{{% cs-module name="Spaces" filename="spaces" %}}
{{% cs-module name="Event replacements" filename="event_replacements" %}}
{{% cs-module name="Event annotations and reactions" filename="event_annotations" %}}
{{% cs-module name="Threading" filename="threading" %}}
{{% cs-module name="Reference relations" filename="reference_relations" %}}

View file

@ -33,7 +33,7 @@ specification.
Content locations are represented as Matrix Content (`mxc://`) URIs. They
look like:
```
```nohighlight
mxc://<server-name>/<media-id>
<server-name> : The name of the homeserver where this content originated, e.g. matrix.org
@ -134,9 +134,14 @@ entity isn't in the room.
`mxc://` URIs are vulnerable to directory traversal attacks such as
`mxc://127.0.0.1/../../../some_service/etc/passwd`. This would cause the
target homeserver to try to access and return this file. As such,
homeservers MUST sanitise `mxc://` URIs by allowing only alphanumeric
(`A-Za-z0-9`), `_` and `-` characters in the `server-name` and
`media-id` values. This set of whitelisted characters allows URL-safe
homeservers MUST sanitise `mxc://` URIs by:
- restricting the `server-name` segment to valid
[server names](/appendices/#server-name)
- allowing only alphanumeric (`A-Za-z0-9`), `_` and `-` characters in
the `media-id` segment
The resulting set of whitelisted characters allows URL-safe
base64 encodings specified in RFC 4648. Applying this character
whitelist is preferable to blacklisting `.` and `/` as there are
techniques around blacklisted characters (percent-encoded characters,

View file

@ -18,7 +18,7 @@ exchange fingerprints between users to build a web of trust.
device. This may include long-term identity keys, and/or one-time
keys.
```
```nohighlight
+----------+ +--------------+
| Bob's HS | | Bob's Device |
+----------+ +--------------+
@ -29,7 +29,7 @@ keys.
2) Alice requests Bob's public identity keys and supported algorithms.
```
```nohighlight
+----------------+ +------------+ +----------+
| Alice's Device | | Alice's HS | | Bob's HS |
+----------------+ +------------+ +----------+
@ -40,7 +40,7 @@ keys.
3) Alice selects an algorithm and claims any one-time keys needed.
```
```nohighlight
+----------------+ +------------+ +----------+
| Alice's Device | | Alice's HS | | Bob's HS |
+----------------+ +------------+ +----------+
@ -491,7 +491,7 @@ this example, Bob's device sends the `m.key.verification.start`, Alice's device
could also send that message. As well, the order of the
`m.key.verification.done` messages could be reversed.
```
```nohighlight
+---------------+ +---------------+ +-------------+ +-------------+
| AliceDevice1 | | AliceDevice2 | | BobDevice1 | | BobDevice2 |
+---------------+ +---------------+ +-------------+ +-------------+
@ -695,7 +695,7 @@ The process between Alice and Bob verifying each other would be:
The wire protocol looks like the following between Alice and Bob's
devices:
```
```nohighlight
+-------------+ +-----------+
| AliceDevice | | BobDevice |
+-------------+ +-----------+
@ -969,7 +969,7 @@ she can trust Bob's device if:
The following diagram illustrates how keys are signed:
```
```nohighlight
+------------------+ .................. +----------------+
| +--------------+ | .................. : | +------------+ |
| | v v v : : v v v | |
@ -1000,7 +1000,7 @@ the user who created them.
The following diagram illustrates Alice's view, hiding the keys and
signatures that she cannot see:
```
```nohighlight
+------------------+ +----------------+ +----------------+
| +--------------+ | | | | +------------+ |
| | v v | v v v | |
@ -1218,7 +1218,7 @@ The binary segment MUST be of the following form:
For example, if Alice displays a QR code encoding the following binary data:
```
```nohighlight
"MATRIX" |ver|mode| len | event ID
4D 41 54 52 49 58 02 00 00 2D 21 41 42 43 44 ...
| user's cross-signing key | other user's cross-signing key | shared secret
@ -1457,8 +1457,8 @@ readers without adding any useful extra information.
##### `m.olm.v1.curve25519-aes-sha2`
The name `m.olm.v1.curve25519-aes-sha2` corresponds to version 1 of the
Olm ratchet, as defined by the [Olm
specification](http://matrix.org/docs/spec/olm.html). This uses:
Olm ratchet, as defined by the [Olm specification](/olm-megolm/olm).
This uses:
- Curve25519 for the initial key agreement.
- HKDF-SHA-256 for ratchet key derivation.
@ -1631,8 +1631,8 @@ This is due to a deprecation of the fields. See
{{% changed-in v="1.3" %}}
The name `m.megolm.v1.aes-sha2` corresponds to version 1 of the Megolm
ratchet, as defined by the [Megolm
specification](http://matrix.org/docs/spec/megolm.html). This uses:
ratchet, as defined by the [Megolm specification](/olm-megolm/megolm).
This uses:
- HMAC-SHA-256 for the hash ratchet.
- HKDF-SHA-256, AES-256 in CBC mode, and 8 byte truncated HMAC-SHA-256
@ -1775,19 +1775,18 @@ property is required for inclusion, though previous versions of the
specification did not have it. In addition to `/versions`, this can be
a way to identify the server's support for fallback keys.
| Parameter | Type | Description |
|----------------------------------|--------------------|------------------------------------------------------------------------------------------------------------------------|
| device_lists | DeviceLists | Optional. Information on e2e device updates. Note: only present on an incremental sync. |
| device_one_time_keys_count | {string: integer} | Optional. For each key algorithm, the number of unclaimed one-time keys currently held on the server for this device. If an algorithm is unlisted, the count for that algorithm is assumed to be zero. If this entire parameter is missing, the count for all algorithms is assumed to be zero. |
| device_unused_fallback_key_types | [string] | **Required.** The unused fallback key algorithms. |
| Parameter | Type | Description |
|----------------------------------|-------------------|------------------------------------------------------------------------------------------------------------------------|
| device_lists | DeviceLists | Optional. Information on e2e device updates. Note: only present on an incremental sync. |
| device_one_time_keys_count | {string: integer} | **Required if any unclaimed one-time keys exist.** For each key algorithm, the number of unclaimed one-time keys currently held on the server for this device. If the count for an algorithm is zero, servers MAY omit that algorithm. If the count for all algorithms is zero, servers MAY omit this parameter entirely. |
| device_unused_fallback_key_types | [string] | **Required.** The unused fallback key algorithms. |
`DeviceLists`
| Parameter | Type | Description |
|------------|-----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| changed | [string] | List of users who have updated their device identity or cross-signing keys, or who now share an encrypted room with the client since the previous sync response. |
| left | [string] | List of users with whom we do not share any encrypted rooms anymore since the previous sync response. |
| Parameter | Type | Description |
|-----------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| changed | [string] | List of users who have updated their device identity or cross-signing keys, or who now share an encrypted room with the client since the previous sync response. |
| left | [string] | List of users with whom we do not share any encrypted rooms anymore since the previous sync response. |
{{% boxes/note %}}
For optimal performance, Alice should be added to `changed` in Bob's

View file

@ -3,6 +3,9 @@
{{% changed-in v="1.7" %}}
{{% changed-in v="1.17" %}}: the legacy push rules that looked for mentions in
the `body` of the event were removed.
This module allows users to "mention" other users and rooms within a room event.
This is primarily used as an indicator that the recipient should receive a notification
about the event.
@ -38,19 +41,18 @@ encrypted as normal. To properly process mentions in encrypted rooms, events
must be decrypted first. See [receiving notifications](#receiving-notifications).
{{% /boxes/warning %}}
Note that, for backwards compatibility, push rules such as [`.m.rule.contains_display_name`](#_m_rule_contains_display_name),
[`.m.rule.contains_user_name`](#_m_rule_contains_user_name), and
[`.m.rule.roomnotif`](#_m_rule_roomnotif) continue to match if the `body` of
the event contains the user's display name or ID. To avoid unintentional notifications,
**it is recommended that clients include a `m.mentions` property on each event**.
(If there are no mentions to include it can be an empty object.)
{{% boxes/rationale %}}
{{% boxes/note %}}
In previous versions of the specification, mentioning users was done by
including the user's display name or the localpart of their Matrix ID and room
mentions were done by including the string "@room" in the plaintext `body` of
the event. This was prone to confusing and buggy behaviour.
{{% /boxes/rationale %}}
the event. When the `m.mentions` field was introduced, those push rules were
disabled if the `m.mentions` field was present.
To avoid unintentional notifications with clients and servers that still use
those push rules, **it is recommended that clients still include a `m.mentions`
property on each event**. (If there are no mentions to include it can be an
empty object.)
{{% /boxes/note %}}
#### Client behaviour

View file

@ -1,7 +1,7 @@
### Push Notifications
```
```nohighlight
+--------------------+ +-------------------+
Matrix HTTP | | | |
Notification Protocol | App Developer | | Device Vendor |
@ -83,7 +83,7 @@ Push Ruleset
: A push ruleset *scopes a set of rules according to some criteria*. For
example, some rules may only be applied for messages from a particular
sender, a particular room, or by default. The push ruleset contains the
entire set of scopes and rules.
entire set of rules.
#### Push Rules
@ -91,10 +91,8 @@ A push rule is a single rule that states under what *conditions* an
event should be passed onto a push gateway and *how* the notification
should be presented. There are different "kinds" of push rules and each
rule has an associated priority. Every push rule MUST have a `kind` and
`rule_id`. The `rule_id` is a unique string within the kind of rule and
its' scope: `rule_ids` do not need to be unique between rules of the
same kind on different devices. Rules may have extra keys depending on
the value of `kind`.
`rule_id`. The `rule_id` is a unique string within the kind of rule.
Rules may have extra keys depending on the value of `kind`.
The different `kind`s of rule, in the order that they are checked, are:
@ -382,6 +380,9 @@ The following `alt_aliases` values will NOT match:
**`contains_display_name`**
{{% changed-in v="1.17" %}}: this condition is deprecated and **should not be
used in new push rules**.
This matches messages where `content.body` contains the owner's display name in
that room. This is a separate condition because display names may change and as such
it would be hard to maintain a rule that matched the user's display name. This
@ -413,6 +414,9 @@ Parameters:
#### Predefined Rules
{{% changed-in v="1.17" %}}: the legacy default push rules that looked for
mentions in the `body` of the event were removed.
Homeservers can specify "server-default rules". They operate at a lower
priority than "user-defined rules", except for the `.m.rule.master` rule
which has always a higher priority than any other rule. The `rule_id`
@ -557,41 +561,6 @@ Definition:
}
```
<a id="_m_rule_contains_display_name"></a> **`.m.rule.contains_display_name`**
{{% changed-in v="1.7" %}}
As of `v1.7`, this rule is deprecated and **should only be enabled if the event
does not have an [`m.mentions` property](#definition-mmentions)**.
Matches any message whose content contains the user's current display name
in the room in which it was sent.
Definition:
```json
{
"rule_id": ".m.rule.contains_display_name",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "contains_display_name"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
},
{
"set_tweak": "highlight"
}
]
}
```
<a id="_m_rule_is_room_mention"></a> **`.m.rule.is_room_mention`**
{{% added-in v="1.7" %}}
@ -626,44 +595,6 @@ Definition:
}
```
<a id="_m_rule_roomnotif"></a> **`.m.rule.roomnotif`**
{{% changed-in v="1.7" %}}
As of `v1.7`, this rule is deprecated and **should only be enabled if the event
does not have an [`m.mentions` property](#definition-mmentions)**.
Matches any message from a sender with the proper power level whose content
contains the text `@room`, signifying the whole room should be notified of
the event.
Definition:
```json
{
"rule_id": ".m.rule.roomnotif",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "content.body",
"pattern": "@room"
},
{
"kind": "sender_notification_permission",
"key": "room"
}
],
"actions": [
"notify",
{
"set_tweak": "highlight"
}
]
}
```
**<a id="mruletombstone"></a>`.m.rule.tombstone`**
Matches any state event whose type is `m.room.tombstone`. This is
@ -776,39 +707,6 @@ Definition:
}
```
##### Default Content Rules
<a id="_m_rule_contains_user_name"></a> **`.m.rule.contains_user_name`**
{{% changed-in v="1.7" %}}
As of `v1.7`, this rule is deprecated and **should only be enabled if the event
does not have an [`m.mentions` property](#definition-mmentions)**.
Matches any message whose content contains the local part of the user's
Matrix ID, separated by word boundaries.
Definition (as a `content` rule):
```json
{
"rule_id": ".m.rule.contains_user_name",
"default": true,
"enabled": true,
"pattern": "[the local part of the user's Matrix ID]",
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
},
{
"set_tweak": "highlight"
}
]
}
```
##### Default Underride Rules
**`.m.rule.call`**

View file

@ -214,7 +214,7 @@ before delivering them to clients.
Some receipts are sent across federation as EDUs with type `m.receipt`. The
format of the EDUs are:
```
```nohighlight
{
<room_id>: {
<receipt_type>: {

View file

@ -20,9 +20,9 @@ Previously, a rich reply could only reference another `m.room.message` event.
{{% 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
representation of the original 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

View file

@ -59,7 +59,7 @@ clients will try to use the default key to decrypt secrets.
Clients that want to present a simplified interface to users by not supporting
multiple keys should use the default key if one is specified. If no default
key is specified, the client may behave as if there is no key is present at
key is specified, the client may behave as if no key is present at
all. When such a client creates a key, it should mark that key as being the
default key.
@ -157,7 +157,7 @@ Some secret is encrypted using keys with ID `key_id_1` and `key_id_2`:
`org.example.some.secret`:
```
```nohighlight
{
"encrypted": {
"key_id_1": {
@ -177,7 +177,7 @@ and the key descriptions for the keys would be:
`m.secret_storage.key.key_id_1`:
```
```nohighlight
{
"name": "Some key",
"algorithm": "m.secret_storage.v1.aes-hmac-sha2",
@ -187,7 +187,7 @@ and the key descriptions for the keys would be:
`m.secret_storage.key.key_id_2`:
```
```nohighlight
{
"name": "Some other key",
"algorithm": "m.secret_storage.v1.aes-hmac-sha2",
@ -199,7 +199,7 @@ If `key_id_1` is the default key, then we also have:
`m.secret_storage.default_key`:
```
```nohighlight
{
"key": "key_id_1"
}
@ -294,7 +294,7 @@ in the `iterations` parameter.
Example:
```
```nohighlight
{
"passphrase": {
"algorithm": "m.pbkdf2",

View file

@ -58,7 +58,7 @@ parent to the room. The `state_key` for the event is the child room's ID.
For example, to achieve the following:
```
```nohighlight
#space:example.org
#general:example.org (!abcdefg:example.org)
!private:example.org

View file

@ -67,7 +67,7 @@ opening an embedded web view.
These steps are illustrated as follows:
```
```nohighlight
Matrix Client Matrix Homeserver Auth Server
| | |
|-------------(0) GET /login----------->| |

View file

@ -44,7 +44,7 @@ If the lookup yields a result for a Matrix User ID then the normal [invite
process](/server-server-api/#inviting-to-a-room) can be initiated. This process
ends up looking like this:
```
```nohighlight
+---------+ +-------------+ +-----------------+
| Client | | Homeserver | | IdentityServer |
+---------+ +-------------+ +-----------------+
@ -74,7 +74,7 @@ the invite on the identity server with a call to
and emit a valid [`m.room.third_party_invite`](#mroomthird_party_invite) event
to the room. This process ends up looking like this:
```
```nohighlight
+---------+ +-------------+ +-----------------+
| Client | | Homeserver | | IdentityServer |
+---------+ +-------------+ +-----------------+
@ -133,7 +133,7 @@ and an identity server IS, the full sequence for a third-party invite
would look like the following. This diagram assumes H1 and H2 are
residents of the room while H3 is attempting to join.
```
```nohighlight
+-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+
| UserA | | ThirdPartyUser | | H1 | | H2 | | H3 | | IS |
+-------+ +-----------------+ +-----+ +-----+ +-----+ +-----+

View file

@ -129,7 +129,7 @@ or not there have been any changes to the Matrix spec.
A call is set up with message events exchanged as follows:
```
```nohighlight
Caller Callee
[Place Call]
m.call.invite ----------->
@ -144,7 +144,7 @@ A call is set up with message events exchanged as follows:
Or a rejected call:
```
```nohighlight
Caller Callee
m.call.invite ------------>
m.call.candidate --------->

View file

@ -2,17 +2,15 @@
title: "Identity Service API"
weight: 40
type: docs
description: |
The Matrix client-server and server-server APIs are largely expressed in
Matrix user identifiers. Sometimes it is useful to refer to users by other
(“third-party”) identifiers such as email addresses or phone numbers. The
Identity Service API describes how mappings between 3PIDs and Matrix user
IDs can be established, validated, and used; in practice this has been
applied to email addresses and phone numbers.
---
The Matrix client-server and server-server APIs are largely expressed in
Matrix user identifiers. From time to time, it is useful to refer to
users by other ("third-party") identifiers, or "3PID"s, e.g. their email
address or phone number. This Identity Service Specification describes
how mappings between third-party identifiers and Matrix user identifiers
can be established, validated, and used. This description technically
may apply to any 3PID, but in practice has only been applied
specifically to email addresses and phone numbers.
## General principles
The purpose of an identity server is to validate, store, and answer

View file

@ -0,0 +1,10 @@
---
title: "Olm & Megolm"
weight: 61
type: docs
---
Matrix uses the Olm and Megolm cryptographic ratchets for [end-to-end encryption](../client-server-api/#end-to-end-encryption).
- [Olm: A Cryptographic Ratchet](/olm-megolm/olm/)
- [Megolm group ratchet](/olm-megolm/megolm/)

View file

@ -0,0 +1,378 @@
---
title: "Megolm group ratchet"
weight: 20
type: docs
---
An AES-based cryptographic ratchet intended for group communications.
## Background
The Megolm ratchet is intended for encrypted messaging applications where there
may be a large number of recipients of each message, thus precluding the use of
peer-to-peer encryption systems such as [Olm][].
It also allows a recipient to decrypt received messages multiple times. For
instance, in client/server applications, a copy of the ciphertext can be stored
on the (untrusted) server, while the client need only store the session keys.
## Overview
Each participant in a conversation uses their own outbound session for
encrypting messages. A session consists of a ratchet and an [Ed25519][] keypair.
Secrecy is provided by the ratchet, which can be wound forwards but not
backwards, and is used to derive a distinct message key for each message.
Authenticity is provided via Ed25519 signatures.
The value of the ratchet, and the public part of the Ed25519 key, are shared
with other participants in the conversation via secure peer-to-peer
channels. Provided that peer-to-peer channel provides authenticity of the
messages to the participants and deniability of the messages to third parties,
the Megolm session will inherit those properties.
## The Megolm ratchet algorithm
The Megolm ratchet \(R_i\) consists of four parts, \(R_{i,j}\) for
\(j \in {0,1,2,3}\). The length of each part depends on the hash function
in use (256 bits for this version of Megolm).
The ratchet is initialised with cryptographically-secure random data, and
advanced as follows:
\[
\begin{aligned}
R_{i,0} &=
\begin{cases}
H_0\left(R_{2^{24}(n-1),0}\right) &\text{if }\exists n | i = 2^{24}n\\
R_{i-1,0} &\text{otherwise}
\end{cases}\\
R_{i,1} &=
\begin{cases}
H_1\left(R_{2^{24}(n-1),0}\right) &\text{if }\exists n | i = 2^{24}n\\
H_1\left(R_{2^{16}(m-1),1}\right) &\text{if }\exists m | i = 2^{16}m\\
R_{i-1,1} &\text{otherwise}
\end{cases}\\
R_{i,2} &=
\begin{cases}
H_2\left(R_{2^{24}(n-1),0}\right) &\text{if }\exists n | i = 2^{24}n\\
H_2\left(R_{2^{16}(m-1),1}\right) &\text{if }\exists m | i = 2^{16}m\\
H_2\left(R_{2^8(p-1),2}\right) &\text{if }\exists p | i = 2^8p\\
R_{i-1,2} &\text{otherwise}
\end{cases}\\
R_{i,3} &=
\begin{cases}
H_3\left(R_{2^{24}(n-1),0}\right) &\text{if }\exists n | i = 2^{24}n\\
H_3\left(R_{2^{16}(m-1),1}\right) &\text{if }\exists m | i = 2^{16}m\\
H_3\left(R_{2^8(p-1),2}\right) &\text{if }\exists p | i = 2^8p\\
H_3\left(R_{i-1,3}\right) &\text{otherwise}
\end{cases}
\end{aligned}
\]
where \(H_0\), \(H_1\), \(H_2\), and \(H_3\) are different hash
functions. In summary: every \(2^8\) iterations, \(R_{i,3}\) is
reseeded from \(R_{i,2}\). Every \(2^{16}\) iterations, \(R_{i,2}\)
and \(R_{i,3}\) are reseeded from \(R_{i,1}\). Every \(2^{24}\)
iterations, \(R_{i,1}\), \(R_{i,2}\) and \(R_{i,3}\) are reseeded
from \(R_{i,0}\).
The complete ratchet value, \(R_{i}\), is hashed to generate the keys used
to encrypt each message. This scheme allows the ratchet to be advanced an
arbitrary amount forwards while needing at most 1020 hash computations. A
client can decrypt chat history onwards from the earliest value of the ratchet
it is aware of, but cannot decrypt history from before that point without
reversing the hash function.
This allows a participant to share its ability to decrypt chat history with
another from a point in the conversation onwards by giving a copy of the
ratchet at that point in the conversation.
## The Megolm protocol
### Session setup
Each participant in a conversation generates their own Megolm session. A
session consists of three parts:
* a 32 bit counter, \(i\).
* an [Ed25519][] keypair, \(K\).
* a ratchet, \(R_i\), which consists of four 256-bit values,
\(R_{i,j}\) for \(j \in {0,1,2,3}\).
The counter \(i\) is initialised to \(0\). A new Ed25519 keypair is
generated for \(K\). The ratchet is simply initialised with 1024 bits of
cryptographically-secure random data.
A single participant may use multiple sessions over the lifetime of a
conversation. The public part of \(K\) is used as an identifier to
discriminate between sessions.
### Sharing session data
To allow other participants in the conversation to decrypt messages, the
session data is formatted as described in [Session-sharing format](#session-sharing-format). It is then
shared with other participants in the conversation via a secure peer-to-peer
channel (such as that provided by [Olm][]).
When the session data is received from other participants, the recipient first
checks that the signature matches the public key. They then store their own
copy of the counter, ratchet, and public key.
### Message encryption
This version of Megolm uses [AES-256][] in [CBC][] mode with [PKCS#7][] padding and
[HMAC-SHA-256][] (truncated to 64 bits). The 256 bit AES key, 256 bit HMAC key,
and 128 bit AES IV are derived from the megolm ratchet \(R_i\):
\[
\begin{aligned}
\mathit{AES\_KEY}_{i}\;\parallel\;\mathit{HMAC\_KEY}_{i}\;\parallel\;\mathit{AES\_IV}_{i}
&= \operatorname{HKDF}\left(0,\,R_{i},\text{"MEGOLM\_KEYS"},\,80\right) \\
\end{aligned}
\]
where \(\parallel\) represents string splitting, and
\(\operatorname{HKDF}\left(\mathit{salt},\,\mathit{IKM},\,\mathit{info},\,L\right)\)
refers to the [HMAC-based key
derivation function][] using using [SHA-256][] as the hash function
([HKDF-SHA-256][]) with a salt value of \(\mathit{salt}\), input key material of
\(\mathit{IKM}\), context string \(\mathit{info}\), and output keying material length of
\(L\) bytes.
The plain-text is encrypted with AES-256, using the key \(\mathit{AES\_KEY}_{i}\)
and the IV \(\mathit{AES\_IV}_{i}\) to give the cipher-text, \(X_{i}\).
The ratchet index \(i\), and the cipher-text \(X_{i}\), are then packed
into a message as described in [Message format](#message-format). Then the entire message
(including the version bytes and all payload bytes) are passed through
HMAC-SHA-256. The first 8 bytes of the MAC are appended to the message.
Finally, the authenticated message is signed using the Ed25519 keypair; the 64
byte signature is appended to the message.
The complete signed message, together with the public part of \(K\) (acting
as a session identifier), can then be sent over an insecure channel. The
message can then be authenticated and decrypted only by recipients who have
received the session data.
### Advancing the ratchet
After each message is encrypted, the ratchet is advanced. This is done as
described in [The Megolm ratchet algorithm](#the-megolm-ratchet-algorithm), using the following definitions:
\[
\begin{aligned}
H_0(A) &\equiv \operatorname{HMAC}(A,\text{``\char`\\x00"}) \\
H_1(A) &\equiv \operatorname{HMAC}(A,\text{``\char`\\x01"}) \\
H_2(A) &\equiv \operatorname{HMAC}(A,\text{``\char`\\x02"}) \\
H_3(A) &\equiv \operatorname{HMAC}(A,\text{``\char`\\x03"}) \\
\end{aligned}
\]
where \(\operatorname{HMAC}(A, T)\) is the HMAC-SHA-256 of ``T``, using ``A`` as the
key.
For outbound sessions, the updated ratchet and counter are stored in the
session.
In order to maintain the ability to decrypt conversation history, inbound
sessions should store a copy of their earliest known ratchet value (unless they
explicitly want to drop the ability to decrypt that history - see [Partial
Forward Secrecy](#partial-forward-secrecy)). They may also choose to cache calculated ratchet values,
but the decision of which ratchet states to cache is left to the application.
## Data exchange formats
### Session sharing format
This format is used for the initial sharing of a Megolm session with other
group participants who need to be able to read messages encrypted by this
session.
The session sharing format is as follows:
```nohighlight
+---+----+--------+--------+--------+--------+------+-----------+
| V | i | R(i,0) | R(i,1) | R(i,2) | R(i,3) | Kpub | Signature |
+---+----+--------+--------+--------+--------+------+-----------+
0 1 5 37 69 101 133 165 229 bytes
```
The version byte, ``V``, is ``"\x02"``.
This is followed by the ratchet index, \(i\), which is encoded as a
big-endian 32-bit integer; the ratchet values \(R_{i,j}\); and the public
part of the Ed25519 keypair \(K\).
The data is then signed using the Ed25519 keypair, and the 64-byte signature is
appended.
### Session export format
Once the session is initially shared with the group participants, each
participant needs to retain a copy of the session if they want to maintain
their ability to decrypt messages encrypted with that session.
For forward-secrecy purposes, a participant may choose to store a ratcheted
version of the session. But since the ratchet index is covered by the
signature, this would invalidate the signature. So we define a similar format,
called the *session export format*, which is identical to the [session sharing
format](#session-sharing-format) except for dropping the signature.
The Megolm session export format is thus as follows:
```nohighlight
+---+----+--------+--------+--------+--------+------+
| V | i | R(i,0) | R(i,1) | R(i,2) | R(i,3) | Kpub |
+---+----+--------+--------+--------+--------+------+
0 1 5 37 69 101 133 165 bytes
```
The version byte, ``V``, is ``"\x01"``.
This is followed by the ratchet index, \(i\), which is encoded as a
big-endian 32-bit integer; the ratchet values \(R_{i,j}\); and the public
part of the Ed25519 keypair \(K\).
### Message format
Megolm messages consist of a one byte version, followed by a variable length
payload, a fixed length message authentication code, and a fixed length
signature.
```nohighlight
+---+------------------------------------+-----------+------------------+
| V | Payload Bytes | MAC Bytes | Signature Bytes |
+---+------------------------------------+-----------+------------------+
0 1 N N+8 N+72 bytes
```
The version byte, ``V``, is ``"\x03"``.
The payload uses a format based on the [Protocol Buffers encoding][]. It
consists of the following key-value pairs:
**Name**|**Tag**|**Type**|**Meaning**
:-----:|:-----:|:-----:|:-----:
Message-Index|0x08|Integer|The index of the ratchet, i
Cipher-Text|0x12|String|The cipher-text, Xi, of the message
Within the payload, integers are encoded using a variable length encoding. Each
integer is encoded as a sequence of bytes with the high bit set followed by a
byte with the high bit clear. The seven low bits of each byte store the bits of
the integer. The least significant bits are stored in the first byte.
Strings are encoded as a variable-length integer followed by the string itself.
Each key-value pair is encoded as a variable-length integer giving the tag,
followed by a string or variable-length integer giving the value.
The payload is followed by the MAC. The length of the MAC is determined by the
authenticated encryption algorithm being used (8 bytes in this version of the
protocol). The MAC protects all of the bytes preceding the MAC.
The length of the signature is determined by the signing algorithm being used
(64 bytes in this version of the protocol). The signature covers all of the
bytes preceding the signature.
## Limitations
### Message Replays
A message can be decrypted successfully multiple times. This means that an
attacker can re-send a copy of an old message, and the recipient will treat it
as a new message.
To mitigate this it is recommended that applications track the ratchet indices
they have received and that they reject messages with a ratchet index that
they have already decrypted.
### Lack of Transcript Consistency
In a group conversation, there is no guarantee that all recipients have
received the same messages. For example, if Alice is in a conversation with Bob
and Charlie, she could send different messages to Bob and Charlie, or could
send some messages to Bob but not Charlie, or vice versa.
Solving this is, in general, a hard problem, particularly in a protocol which
does not guarantee in-order message delivery. For now it remains the subject of
future research.
### Lack of Backward Secrecy
[Backward secrecy](https://intensecrypto.org/public/lec_08_hash_functions_part2.html#sec-forward-and-backward-secrecy)
(also called 'future secrecy' or 'post-compromise security') is the property
that if current private keys are compromised, an attacker cannot decrypt
future messages in a given session. In other words, when looking
**backwards** in time at a compromise which has already happened, **current**
messages are still secret.
By itself, Megolm does not possess this property: once the key to a Megolm
session is compromised, the attacker can decrypt any message that was
encrypted using a key derived from the compromised or subsequent ratchet
values.
In order to mitigate this, the application should ensure that Megolm sessions
are not used indefinitely. Instead it should periodically start a new session,
with new keys shared over a secure channel.
<!-- TODO: Can we recommend sensible lifetimes for Megolm sessions? Probably
depends how paranoid we're feeling, but some guidelines might be useful. -->
### Partial Forward Secrecy
[Forward secrecy](https://intensecrypto.org/public/lec_08_hash_functions_part2.html#sec-forward-and-backward-secrecy)
(also called 'perfect forward secrecy') is the property that if the current
private keys are compromised, an attacker cannot decrypt *past* messages in
a given session. In other words, when looking **forwards** in time towards a
potential future compromise, **current** messages will be secret.
In Megolm, each recipient maintains a record of the ratchet value which allows
them to decrypt any messages sent in the session after the corresponding point
in the conversation. If this value is compromised, an attacker can similarly
decrypt past messages which were encrypted by a key derived from the
compromised or subsequent ratchet values. This gives 'partial' forward
secrecy.
To mitigate this issue, the application should offer the user the option to
discard historical conversations, by winding forward any stored ratchet values,
or discarding sessions altogether.
### Dependency on secure channel for key exchange
The design of the Megolm ratchet relies on the availability of a secure
peer-to-peer channel for the exchange of session keys. Any vulnerabilities in
the underlying channel are likely to be amplified when applied to Megolm
session setup.
For example, if the peer-to-peer channel is vulnerable to an unknown key-share
attack, the entire Megolm session become similarly vulnerable. For example:
Alice starts a group chat with Eve, and shares the session keys with Eve. Eve
uses the unknown key-share attack to forward the session keys to Bob, who
believes Alice is starting the session with him. Eve then forwards messages
from the Megolm session to Bob, who again believes they are coming from
Alice. Provided the peer-to-peer channel is not vulnerable to this attack, Bob
will realise that the key-sharing message was forwarded by Eve, and can treat
the Megolm session as a forgery.
A second example: if the peer-to-peer channel is vulnerable to a replay
attack, this can be extended to entire Megolm sessions.
## License
The Megolm specification (this document) is licensed under the Apache License,
Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.
[Ed25519]: http://ed25519.cr.yp.to/
[HMAC-based key derivation function]: https://tools.ietf.org/html/rfc5869
[HKDF-SHA-256]: https://tools.ietf.org/html/rfc5869
[HMAC-SHA-256]: https://tools.ietf.org/html/rfc2104
[SHA-256]: https://tools.ietf.org/html/rfc6234
[AES-256]: http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
[CBC]: http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
[PKCS#7]: https://tools.ietf.org/html/rfc2315
[Olm]: https://gitlab.matrix.org/matrix-org/olm/blob/master/docs/olm.md
[Protocol Buffers encoding]: https://developers.google.com/protocol-buffers/docs/encoding

334
content/olm-megolm/olm.md Normal file
View file

@ -0,0 +1,334 @@
---
title: "Olm: A Cryptographic Ratchet"
weight: 10
type: docs
---
An implementation of the double cryptographic ratchet described by
https://whispersystems.org/docs/specifications/doubleratchet/.
## Notation
This document uses \(\parallel\) to represent string concatenation. When
\(\parallel\) appears on the right hand side of an \(=\) it means that
the inputs are concatenated. When \(\parallel\) appears on the left hand
side of an \(=\) it means that the output is split.
When this document uses \(\operatorname{ECDH}\left(K_A,K_B\right)\) it means
that each party computes a Diffie-Hellman agreement using their private key
and the remote party's public key.
So party \(A\) computes \(\operatorname{ECDH}\left(K_B^{public},K_A^{private}\right)\)
and party \(B\) computes \(\operatorname{ECDH}\left(K_A^{public},K_B^{private}\right)\).
Where this document uses \(\operatorname{HKDF}\left(salt,IKM,info,L\right)\) it
refers to the [HMAC-based key derivation function][] with a salt value of
\(salt\), input key material of \(IKM\), context string \(info\),
and output keying material length of \(L\) bytes.
## The Olm Algorithm
### Initial setup
The setup takes four [Curve25519][] inputs: Identity keys for Alice and Bob,
\(I_A\) and \(I_B\), and one-time keys for Alice and Bob,
\(E_A\) and \(E_B\). A shared secret, \(S\), is generated using
[Triple Diffie-Hellman][]. The initial 256 bit root key, \(R_0\), and 256
bit chain key, \(C_{0,0}\), are derived from the shared secret using an
HMAC-based Key Derivation Function using [SHA-256][] as the hash function
([HKDF-SHA-256][]) with default salt and ``"OLM_ROOT"`` as the info.
\[
\begin{aligned}
S&=\operatorname{ECDH}\left(I_A,E_B\right)\;\parallel\;
\operatorname{ECDH}\left(E_A,I_B\right)\;\parallel\;
\operatorname{ECDH}\left(E_A,E_B\right)\\
R_0\;\parallel\;C_{0,0}&=
\operatorname{HKDF}\left(0,S,\text{``OLM\_ROOT"},64\right)
\end{aligned}
\]
### Advancing the root key
Advancing a root key takes the previous root key, \(R_{i-1}\), and two
Curve25519 inputs: the previous ratchet key, \(T_{i-1}\), and the current
ratchet key \(T_i\). The even ratchet keys are generated by Alice.
The odd ratchet keys are generated by Bob. A shared secret is generated
using Diffie-Hellman on the ratchet keys. The next root key, \(R_i\), and
chain key, \(C_{i,0}\), are derived from the shared secret using
[HKDF-SHA-256][] using \(R_{i-1}\) as the salt and ``"OLM_RATCHET"`` as the
info.
\[
\begin{aligned}
R_i\;\parallel\;C_{i,0}&=
\operatorname{HKDF}\left(
R_{i-1},
\operatorname{ECDH}\left(T_{i-1},T_i\right),
\text{``OLM\_RATCHET"},
64
\right)
\end{aligned}
\]
### Advancing the chain key
Advancing a chain key takes the previous chain key, \(C_{i,j-1}\). The next
chain key, \(C_{i,j}\), is the [HMAC-SHA-256][] of ``"\x02"`` using the
previous chain key as the key.
\[
\begin{aligned}
C_{i,j}&=\operatorname{HMAC}\left(C_{i,j-1},\text{``\char`\\x02"}\right)
\end{aligned}
\]
### Creating a message key
Creating a message key takes the current chain key, \(C_{i,j}\). The
message key, \(M_{i,j}\), is the [HMAC-SHA-256][] of ``"\x01"`` using the
current chain key as the key. The message keys where \(i\) is even are used
by Alice to encrypt messages. The message keys where \(i\) is odd are used
by Bob to encrypt messages.
\[
\begin{aligned}
M_{i,j}&=\operatorname{HMAC}\left(C_{i,j},\text{``\char`\\x01"}\right)
\end{aligned}
\]
## The Olm Protocol
### Creating an outbound session
Bob publishes the public parts of his identity key, \(I_B\), and some
single-use one-time keys \(E_B\).
Alice downloads Bob's identity key, \(I_B\), and a one-time key,
\(E_B\). She generates a new single-use key, \(E_A\), and computes a
root key, \(R_0\), and a chain key \(C_{0,0}\). She also generates a
new ratchet key \(T_0\).
### Sending the first pre-key messages
Alice computes a message key, \(M_{0,j}\), and a new chain key,
\(C_{0,j+1}\), using the current chain key. She replaces the current chain
key with the new one.
Alice encrypts her plain-text with the message key, \(M_{0,j}\), using an
authenticated encryption scheme (see below) to get a cipher-text,
\(X_{0,j}\).
She then sends the following to Bob:
* The public part of her identity key, \(I_A\)
* The public part of her single-use key, \(E_A\)
* The public part of Bob's single-use key, \(E_B\)
* The current chain index, \(j\)
* The public part of her ratchet key, \(T_0\)
* The cipher-text, \(X_{0,j}\)
Alice will continue to send pre-key messages until she receives a message from
Bob.
### Creating an inbound session from a pre-key message
Bob receives a pre-key message as above.
Bob looks up the private part of his single-use key, \(E_B\). He can now
compute the root key, \(R_0\), and the chain key, \(C_{0,0}\), from
\(I_A\), \(E_A\), \(I_B\), and \(E_B\).
Bob then advances the chain key \(j\) times, to compute the chain key used
by the message, \(C_{0,j}\). He now creates the
message key, \(M_{0,j}\), and attempts to decrypt the cipher-text,
\(X_{0,j}\). If the cipher-text's authentication is correct then Bob can
discard the private part of his single-use one-time key, \(E_B\).
Bob stores Alice's initial ratchet key, \(T_0\), until he wants to
send a message.
### Sending normal messages
Once a message has been received from the other side, a session is considered
established, and a more compact form is used.
To send a message, the user checks if they have a sender chain key,
\(C_{i,j}\). Alice uses chain keys where \(i\) is even. Bob uses chain
keys where \(i\) is odd. If the chain key doesn't exist then a new ratchet
key \(T_i\) is generated and a new root key \(R_i\) and chain key
\(C_{i,0}\) are computed using \(R_{i-1}\), \(T_{i-1}\) and
\(T_i\).
A message key,
\(M_{i,j}\) is computed from the current chain key, \(C_{i,j}\), and
the chain key is replaced with the next chain key, \(C_{i,j+1}\). The
plain-text is encrypted with \(M_{i,j}\), using an authenticated encryption
scheme (see below) to get a cipher-text, \(X_{i,j}\).
The user then sends the following to the recipient:
* The current chain index, \(j\)
* The public part of the current ratchet key, \(T_i\)
* The cipher-text, \(X_{i,j}\)
### Receiving messages
The user receives a message as above with the sender's current chain index, \(j\),
the sender's ratchet key, \(T_i\), and the cipher-text, \(X_{i,j}\).
The user checks if they have a receiver chain with the correct
\(i\) by comparing the ratchet key, \(T_i\). If the chain doesn't exist
then they compute a new root key, \(R_i\), and a new receiver chain, with
chain key \(C_{i,0}\), using \(R_{i-1}\), \(T_{i-1}\) and
\(T_i\).
If the \(j\) of the message is less than
the current chain index on the receiver then the message may only be decrypted
if the receiver has stored a copy of the message key \(M_{i,j}\). Otherwise
the receiver computes the chain key, \(C_{i,j}\). The receiver computes the
message key, \(M_{i,j}\), from the chain key and attempts to decrypt the
cipher-text, \(X_{i,j}\).
If the decryption succeeds the receiver updates the chain key for \(T_i\)
with \(C_{i,j+1}\) and stores the message keys that were skipped in the
process so that they can decode out of order messages. If the receiver created
a new receiver chain then they discard their current sender chain so that
they will create a new chain when they next send a message.
## The Olm Message Format
Olm uses two types of messages. The underlying transport protocol must provide
a means for recipients to distinguish between them.
### Normal Messages
Olm messages start with a one byte version followed by a variable length
payload followed by a fixed length message authentication code.
```nohighlight
+--------------+------------------------------------+-----------+
| Version Byte | Payload Bytes | MAC Bytes |
+--------------+------------------------------------+-----------+
```
The version byte is ``"\x03"``.
The payload consists of key-value pairs where the keys are integers and the
values are integers and strings. The keys are encoded as a variable length
integer tag where the 3 lowest bits indicates the type of the value:
0 for integers, 2 for strings. If the value is an integer then the tag is
followed by the value encoded as a variable length integer. If the value is
a string then the tag is followed by the length of the string encoded as
a variable length integer followed by the string itself.
Olm uses a variable length encoding for integers. Each integer is encoded as a
sequence of bytes with the high bit set followed by a byte with the high bit
clear. The seven low bits of each byte store the bits of the integer. The least
significant bits are stored in the first byte.
**Name**|**Tag**|**Type**|**Meaning**
:-----:|:-----:|:-----:|:-----:
Ratchet-Key|0x0A|String|The public part of the ratchet key, Ti, of the message
Chain-Index|0x10|Integer|The chain index, j, of the message
Cipher-Text|0x22|String|The cipher-text, Xi,j, of the message
The length of the MAC is determined by the authenticated encryption algorithm
being used. (Olm version 1 uses [HMAC-SHA-256][], truncated to 8 bytes). The
MAC protects all of the bytes preceding the MAC.
### Pre-Key Messages
Olm pre-key messages start with a one byte version followed by a variable
length payload.
```nohighlight
+--------------+------------------------------------+
| Version Byte | Payload Bytes |
+--------------+------------------------------------+
```
The version byte is ``"\x03"``.
The payload uses the same key-value format as for normal messages.
**Name**|**Tag**|**Type**|**Meaning**
:-----:|:-----:|:-----:|:-----:
One-Time-Key|0x0A|String|The public part of Bob's single-use key, Eb.
Base-Key|0x12|String|The public part of Alice's single-use key, Ea.
Identity-Key|0x1A|String|The public part of Alice's identity key, Ia.
Message|0x22|String|An embedded Olm message with its own version and MAC.
## Olm Authenticated Encryption
### Version 1
Version 1 of Olm uses [AES-256][] in [CBC][] mode with [PKCS#7][] padding for
encryption and [HMAC-SHA-256][] (truncated to 64 bits) for authentication. The
256 bit AES key, 256 bit HMAC key, and 128 bit AES IV are derived from the
message key using [HKDF-SHA-256][] using the default salt and an info of
``"OLM_KEYS"``.
\[
\begin{aligned}
AES\_KEY_{i,j}\;\parallel\;HMAC\_KEY_{i,j}\;\parallel\;AES\_IV_{i,j}
&= \operatorname{HKDF}\left(0,M_{i,j},\text{``OLM\_KEYS"},80\right)
\end{aligned}
\]
The plain-text is encrypted with AES-256, using the key \(AES\_KEY_{i,j}\)
and the IV \(AES\_IV_{i,j}\) to give the cipher-text, \(X_{i,j}\).
Then the entire message (including the Version Byte and all Payload Bytes) are
passed through [HMAC-SHA-256][]. The first 8 bytes of the MAC are appended to the message.
## Message authentication concerns
To avoid unknown key-share attacks, the application must include identifying
data for the sending and receiving user in the plain-text of (at least) the
pre-key messages. Such data could be a user ID, a telephone number;
alternatively it could be the public part of a keypair which the relevant user
has proven ownership of.
### Example attacks
1. Alice publishes her public [Curve25519][] identity key, \(I_A\). Eve
publishes the same identity key, claiming it as her own. Bob downloads
Eve's keys, and associates \(I_A\) with Eve. Alice sends a message to
Bob; Eve intercepts it before forwarding it to Bob. Bob believes the
message came from Eve rather than Alice.
This is prevented if Alice includes her user ID in the plain-text of the
pre-key message, so that Bob can see that the message was sent by Alice
originally.
2. Bob publishes his public [Curve25519][] identity key, \(I_B\). Eve
publishes the same identity key, claiming it as her own. Alice downloads
Eve's keys, and associates \(I_B\) with Eve. Alice sends a message to
Eve; Eve cannot decrypt it, but forwards it to Bob. Bob believes the
Alice sent the message to him, whereas Alice intended it to go to Eve.
This is prevented by Alice including the user ID of the intended recpient
(Eve) in the plain-text of the pre-key message. Bob can now tell that the
message was meant for Eve rather than him.
## IPR
The Olm specification (this document) is hereby placed in the public domain.
## Feedback
Can be sent to olm at matrix.org.
## Acknowledgements
The ratchet that Olm implements was designed by Trevor Perrin and Moxie
Marlinspike - details at https://whispersystems.org/docs/specifications/doubleratchet/. Olm is
an entirely new implementation written by the Matrix.org team.
[Curve25519]: http://cr.yp.to/ecdh.html
[Triple Diffie-Hellman]: https://whispersystems.org/blog/simplifying-otr-deniability/
[HMAC-based key derivation function]: https://tools.ietf.org/html/rfc5869
[HKDF-SHA-256]: https://tools.ietf.org/html/rfc5869
[HMAC-SHA-256]: https://tools.ietf.org/html/rfc2104
[SHA-256]: https://tools.ietf.org/html/rfc6234
[AES-256]: http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
[CBC]: http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
[PKCS#7]: https://tools.ietf.org/html/rfc2315

View file

@ -1,6 +1,6 @@
---
title: "Spec Change Proposals"
weight: 60
weight: 62
type: docs
---
@ -281,7 +281,7 @@ corresponding labels for each stage on the
[matrix-spec-proposals](https://github.com/matrix-org/matrix-spec-proposals)
pull request trackers.
```
```nohighlight
+ +
Proposals | Spec PRs | Additional States
+-------+ | +------+ | +---------------+

View file

@ -2,19 +2,18 @@
title: "Push Gateway API"
weight: 50
type: docs
description: |
Clients may want to receive push notifications when events are received at the
homeserver. This is managed by a distinct entity called the Push Gateway.
---
Clients may want to receive push notifications when events are received
at the homeserver. This is managed by a distinct entity called the Push
Gateway.
## Overview
A client's homeserver forwards information about received events to the
push gateway. The gateway then submits a push notification to the push
notification provider (e.g. APNS, GCM).
```
```nohighlight
+--------------------+ +-------------------+
Matrix HTTP | | | |
Notification Protocol | App Developer | | Device Vendor |

View file

@ -17,6 +17,9 @@ is met:
2. The domain of the redaction event's `sender` matches that of the
original event's `sender`.
Note that the first condition holds true even when the `sender` doesn't have a
high enough power level to send the type of event that they're redacting.
If the server would apply a redaction, the redaction event is also sent
to clients. Otherwise, the server simply waits for a valid partner event
to arrive where it can then re-check the above.

View file

@ -74,7 +74,7 @@ The rules are as follows:
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.
users or is not a joined member of the room, reject.
3. Otherwise, allow.
6. If the `join_rule` is `public`, allow.
7. Otherwise, reject.

View file

@ -18,7 +18,7 @@ refined in [room version 9](/rooms/v9)).
Clients should render the new join rule accordingly for such rooms. For example:
```
```nohighlight
This room is:
[ ] Public
[x] Private
@ -150,7 +150,7 @@ The rules are as follows:
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.
users or is not a joined member of the room, reject.
3. Otherwise, allow.
6. If the `join_rule` is `public`, allow.
7. Otherwise, reject.

View file

@ -157,7 +157,7 @@ The rules are as follows:
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.
users or is not a joined member of the room, reject.
3. Otherwise, allow.
6. If the `join_rule` is `public`, allow.
7. Otherwise, reject.

View file

@ -141,7 +141,7 @@ The rules are as follows:
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.
users or is not a joined member of the room, reject.
3. Otherwise, allow.
6. If the `join_rule` is `public`, allow.
7. Otherwise, reject.

View file

@ -2,49 +2,46 @@
title: "Server-Server API"
weight: 20
type: docs
description: |
Matrix homeservers use the Federation APIs (also known as server-server APIs)
to communicate with each other. Homeservers use these APIs to push messages in
real-time, retrieve historic messages, and query profile or presence
information about users on other servers. The APIs are implemented over HTTPS,
with authentication provided by public key signatures both at the TLS
transport layer and in HTTP Authorization headers.
There are three main kinds of communication that occur between
homeservers:
Persistent Data Units (PDUs):
These events are broadcast from one homeserver to any others that have
joined the same room (identified by Room ID). They are persisted in
long-term storage and record the history of messages and state for a
room.
Like email, it is the responsibility of the originating server of a PDU
to deliver that event to its recipient servers. However PDUs are signed
using the originating server's private key so that it is possible to
deliver them through third-party servers.
Ephemeral Data Units (EDUs):
These events are pushed between pairs of homeservers. They are not
persisted and are not part of the history of a room, nor does the
receiving homeserver have to reply to them.
Queries:
These are single request/response interactions between a given pair of
servers, initiated by one side sending an HTTPS GET request to obtain
some information, and responded by the other. They are not persisted and
contain no long-term significant history. They simply request a snapshot
state at the instant the query is made.
EDUs and PDUs are further wrapped in an envelope called a Transaction,
which is transferred from the origin to the destination homeserver using
an HTTPS PUT request.
---
Matrix homeservers use the Federation APIs (also known as server-server
APIs) to communicate with each other. Homeservers use these APIs to push
messages to each other in real-time, to retrieve historic messages from
each other, and to query profile and presence information about users on
each other's servers.
The APIs are implemented using HTTPS requests between each of the
servers. These HTTPS requests are strongly authenticated using public
key signatures at the TLS transport layer and using public key
signatures in HTTP Authorization headers at the HTTP layer.
There are three main kinds of communication that occur between
homeservers:
Persistent Data Units (PDUs):
These events are broadcast from one homeserver to any others that have
joined the same room (identified by Room ID). They are persisted in
long-term storage and record the history of messages and state for a
room.
Like email, it is the responsibility of the originating server of a PDU
to deliver that event to its recipient servers. However PDUs are signed
using the originating server's private key so that it is possible to
deliver them through third-party servers.
Ephemeral Data Units (EDUs):
These events are pushed between pairs of homeservers. They are not
persisted and are not part of the history of a room, nor does the
receiving homeserver have to reply to them.
Queries:
These are single request/response interactions between a given pair of
servers, initiated by one side sending an HTTPS GET request to obtain
some information, and responded by the other. They are not persisted and
contain no long-term significant history. They simply request a snapshot
state at the instant the query is made.
EDUs and PDUs are further wrapped in an envelope called a Transaction,
which is transferred from the origin to the destination homeserver using
an HTTPS PUT request.
## API standards
The mandatory baseline for server-server communication in Matrix is
@ -289,7 +286,7 @@ and any query parameters if present, but should not include the leading
Step 1 sign JSON:
```
```nohighlight
{
"method": "POST",
"uri": "/target",
@ -822,7 +819,7 @@ ResidentServer->JoiningServer: send_join response
JoiningServer->Client: join response
-->
```
```nohighlight
+---------+ +---------------+ +-----------------+ +-----------------+
| Client | | JoiningServer | | DirectoryServer | | ResidentServer |
+---------+ +---------------+ +-----------------+ +-----------------+

View file

@ -99,6 +99,10 @@ paths:
has been removed, making this endpoint behave as though it was `false`.
This results in this endpoint being an equivalent to `/3pid/bind` rather
than dual-purpose.
This endpoint uses [capabilities negotiation](/client-server-api/#capabilities-negotiation).
Clients SHOULD check the value of the [`m.3pid_changes` capability](/client-server-api/#m3pid_changes-capability)
to determine if this endpoint is available.
operationId: post3PIDs
deprecated: true
security:
@ -202,6 +206,10 @@ paths:
Homeservers should prevent the caller from adding a 3PID to their account if it has
already been added to another user's account on the homeserver.
This endpoint uses [capabilities negotiation](/client-server-api/#capabilities-negotiation).
Clients SHOULD check the value of the [`m.3pid_changes` capability](/client-server-api/#m3pid_changes-capability)
to determine if this endpoint is available.
{{% boxes/warning %}}
Since this endpoint uses User-Interactive Authentication, it cannot be used when the access token was obtained
via the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
@ -331,6 +339,10 @@ paths:
Unlike other endpoints, this endpoint does not take an `id_access_token`
parameter because the homeserver is expected to sign the request to the
identity server instead.
This endpoint uses [capabilities negotiation](/client-server-api/#capabilities-negotiation).
Clients SHOULD check the value of the [`m.3pid_changes` capability](/client-server-api/#m3pid_changes-capability)
to determine if this endpoint is available.
operationId: delete3pidFromAccount
security:
- accessTokenQuery: []

View file

@ -379,7 +379,8 @@ paths:
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.
The differences from the [OpenGraph protocol](https://ogp.me/) are
described here.
content:
application/json:
schema:
@ -394,6 +395,9 @@ paths:
format: uri
description: An [`mxc://` URI](/client-server-api/#matrix-content-mxc-uris) to
the image. Omitted if there is no image.
additionalProperties:
description: |-
Additional properties as per the [OpenGraph](https://ogp.me/) protocol.
examples:
response:
value: {

View file

@ -605,7 +605,8 @@ paths:
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.
The differences from the [OpenGraph](https://ogp.me/) protocol are
described here.
content:
application/json:
schema:
@ -620,6 +621,9 @@ paths:
format: uri
description: An [`mxc://` URI](/client-server-api/#matrix-content-mxc-uris) to
the image. Omitted if there is no image.
additionalProperties:
description: |-
Additional properties as per the [OpenGraph](https://ogp.me/) protocol.
examples:
response:
value: {

View file

@ -21,13 +21,17 @@ paths:
x-addedInMatrixVersion: "1.1"
x-changedInMatrixVersion:
"1.11": UIA is not always required for this endpoint.
"1.17": |-
This endpoint no longer requires User-Interactive Authentication when used by an
application service.
summary: Upload cross-signing keys.
description: |-
Publishes cross-signing keys for the user.
This API endpoint uses the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api).
This API endpoint uses the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api),
except when used by an application service.
User-Interactive Authentication MUST be performed, except in these cases:
User-Interactive Authentication MUST be performed for regular clients, except in these cases:
- there is no existing cross-signing master key uploaded to the homeserver, OR
- there is 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
@ -40,10 +44,12 @@ paths:
makes this endpoint idempotent in the case where the response is lost over the network,
which would otherwise cause a UIA challenge upon retry.
{{% boxes/warning %}}
When this endpoint requires User-Interactive Authentication, it cannot be used when the access token was obtained
{{% boxes/note %}}
When this endpoint requires User-Interactive Authentication,
it uses the [`m.oauth`](/client-server-api/#oauth-authentication)
authentication type if the access token was obtained
via the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
{{% /boxes/warning %}}
{{% /boxes/note %}}
operationId: uploadCrossSigningKeys
security:
- accessTokenQuery: []

View file

@ -0,0 +1,30 @@
# Copyright 2025 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
type: object
title: m.oauth params
description: Schema for `m.oauth` entry in the `params` object in a User-Interactive Authentication response.
required: ['url']
properties:
url:
type: string
format: uri
description: |
A URL pointing to the homeserver's OAuth account management web UI
where the user can approve the action. MUST be a valid URI with scheme
`http://` or `https://`, the latter being RECOMMENDED.
pattern: "^https?://"
example: {
"url": "https://example.org/account/reset-cross-signing"
}

View file

@ -34,24 +34,6 @@ properties:
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": [],
@ -113,12 +95,14 @@ example: {
],
"conditions": [
{
"kind": "contains_display_name"
"kind": "event_property_contains",
"key": "content.m\\.mentions.user_ids",
"value": "@alice:example.com"
}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.contains_display_name"
"rule_id": ".m.rule.is_user_mention"
},
{
"actions": [

View file

@ -87,8 +87,21 @@ paths:
tags:
- Device management
put:
summary: Update a device
description: Updates the metadata on the given device.
summary: Create or update a device
x-changedInMatrixVersion:
"1.17": The ability to create new devices was added.
description: |-
Updates the metadata on the given device, or creates a new device.
The ability to create new devices is only available to application
services: regular clients may only update existing devices.
When a new device was created, the homeserver MUST return a 201 HTTP
status code. It MUST return a 200 HTTP status code if a device was
updated.
This endpoint is rate-limited for device creation. Servers MAY use login
rate limits.
operationId: updateDevice
security:
- accessTokenQuery: []
@ -127,19 +140,34 @@ paths:
examples:
response:
value: {}
"201":
description: |-
The device was successfully created by the application service.
content:
application/json:
schema:
type: object
examples:
response:
value: {}
"404":
description: The current user has no device with the given ID.
tags:
- Device management
delete:
summary: Delete a device
x-changedInMatrixVersion:
"1.17": |-
This endpoint no longer requires User-Interactive Authentication when used by an
application service.
description: |-
This API endpoint uses the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api).
This API endpoint uses the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api),
except when used by an application service.
Deletes the given device, and invalidates any access token associated with it.
{{% boxes/warning %}}
Since this endpoint uses User-Interactive Authentication, it cannot be used when the access token was obtained
When this endpoint requires User-Interactive Authentication, it cannot be used when the access token was obtained
via the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
{{% /boxes/warning %}}
operationId: deleteDevice
@ -190,13 +218,18 @@ paths:
/delete_devices:
post:
summary: Bulk deletion of devices
x-changedInMatrixVersion:
"1.17": |-
This endpoint no longer requires User-Interactive Authentication when used by an
application service.
description: |-
This API endpoint uses the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api).
This API endpoint uses the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api),
except when used by an application service.
Deletes the given devices, and invalidates any access token associated with them.
{{% boxes/warning %}}
Since this endpoint uses User-Interactive Authentication, it cannot be used when the access token was obtained
When this endpoint requires User-Interactive Authentication, it cannot be used when the access token was obtained
via the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
{{% /boxes/warning %}}
operationId: deleteDevices

View file

@ -243,8 +243,13 @@ paths:
}
}
"400":
description: Part of the request was invalid. For example, the login type may
not be recognised.
description: |-
Part of the request was invalid. For example, the login type may not be recognised.
Specific error codes used with this status code include:
* {{% added-in v="1.17" %}} `M_APPSERVICE_LOGIN_UNSUPPORTED`: an application service
used the `m.login.application_service` type, but the server doesn't support logging
in via the Legacy authentication API.
content:
application/json:
schema:
@ -262,6 +267,8 @@ paths:
or the requested device ID is the same as a cross-signing key
ID.
* `M_USER_DEACTIVATED`: The user has been deactivated.
Servers MAY instead use `M_FORBIDDEN` when they can no longer authenticate
the deactivated user (e.g. their password has been wiped).
content:
application/json:
schema:

View file

@ -324,7 +324,7 @@ paths:
This endpoint was deprecated in r0 of this specification. Clients
should instead call the
[/rooms/{roomId}/event/{eventId}](/client-server-api/#get_matrixclientv3roomsroomideventeventid) API
or the [/rooms/{roomId}/context/{eventId](/client-server-api/#get_matrixclientv3roomsroomidcontexteventid) API.
or the [/rooms/{roomId}/context/{eventId}](/client-server-api/#get_matrixclientv3roomsroomidcontexteventid) API.
operationId: getOneEvent
security:
- accessTokenQuery: []

View file

@ -34,6 +34,10 @@ paths:
valid access token is provided. The homeserver SHOULD NOT revoke the
access token provided in the request. Whether other access tokens for
the user are revoked depends on the request parameters.
This endpoint uses [capabilities negotiation](/client-server-api/#capabilities-negotiation).
Clients SHOULD check the value of the [`m.change_password` capability](/client-server-api/#mchange_password-capability)
to determine if this endpoint is available.
security:
- {}
- accessTokenQuery: []

View file

@ -59,6 +59,7 @@ paths:
example: "!somewhere:over.the.rainbow"
schema:
type: string
required: true
responses:
"200":
description: The events received, which may be none.

View file

@ -29,6 +29,11 @@ paths:
Servers MAY reject `null` values. Servers that accept `null` values SHOULD store
them rather than treating `null` as a deletion request. Clients that want to delete a
field, including its key and value, SHOULD use the `DELETE` endpoint instead.
This endpoint uses [capabilities negotiation](/client-server-api/#capabilities-negotiation)
depending on the `keyName`. Clients SHOULD check the value of the
[`m.profile_fields` capability](/client-server-api/#mprofile_fields-capability) to detect
which `keyName`s they are allowed to modify.
operationId: setProfileField
security:
- accessTokenQuery: []

View file

@ -230,11 +230,14 @@ paths:
format:
type: string
description: |-
The format to send notifications in to Push Gateways if the
`kind` is `http`. The details about what fields the
homeserver should send to the push gateway are defined in the
[Push Gateway Specification](/push-gateway-api/). Currently the only format
available is 'event_id_only'.
The format in which to send notifications to the push gateway
if the `kind` is `http`. The details about what fields the
homeserver should include are defined in the
[Push Gateway Specification](/push-gateway-api/). If omitted,
the server is expected to populate all of the event-related fields
specified in [`/_matrix/push/v1/notify`](/push-gateway-api/#post_matrixpushv1notify).
enum:
- "event_id_only"
append:
type: boolean
description: |-

View file

@ -26,9 +26,9 @@ paths:
This cannot be undone.
Any user with a power level greater than or equal to the `m.room.redaction`
event power level may send redaction events in the room. If the user's power
level is also greater than or equal to the `redact` power level of the room,
the user may redact events sent by other users.
event power level may send redactions for their own events in the room. If
the user's power level is also greater than or equal to the `redact` power
level of the room, the user may redact events sent by other users.
Server administrators may redact events sent by users on their server.
operationId: redactEvent

View file

@ -60,6 +60,18 @@ paths:
Any user ID returned by this API must conform to the grammar given in the
[Matrix specification](/appendices/#user-identifiers).
{{% boxes/note %}}
{{% added-in v="1.17" %}}
Even if the server doesn't support the Legacy authentication API, it
MUST support this endpoint for application services to be able to
[create users](/application-service-api/#server-admin-style-permissions).
In that case application services MUST set the `"inhibit_login": true`
parameter as they cannot use it to log in as users. If the
`inhibit_login` parameter is not set to `true`, the server MUST return a
400 HTTP status code with an `M_APPSERVICE_LOGIN_UNSUPPORTED` error code.
{{% /boxes/note %}}
operationId: register
parameters:
- in: query
@ -203,6 +215,9 @@ paths:
* `M_INVALID_USERNAME` : The desired user ID is not a valid user name.
* `M_EXCLUSIVE` : The desired user ID is in the exclusive namespace
claimed by an application service.
* {{% added-in v="1.17" %}} `M_APPSERVICE_LOGIN_UNSUPPORTED`: an application service
used the `m.login.application_service` type without setting `inhibit_login` to `true`,
but the server doesn't support logging in via the Legacy authentication API.
These errors may be returned at any stage of the registration process,
including after authentication if the requested user ID was registered

View file

@ -133,10 +133,15 @@ paths:
sync and the **start** of the timeline in `state` and MUST omit
`state_after`.
Even if this is set to `true`, clients MUST update their local state
with events in `state` and `timeline` if `state_after` is missing in
the response, for compatibility with servers that don't support this
parameter.
Servers MAY implement this parameter ahead of declaring support for
the version of the spec in which it was introduced. Consequently,
clients MAY set this parameter to `true` regardless of the
[`/versions`](/client-server-api/#get_matrixclientversions) response.
If they do, they can infer whether the server actually supports this
parameter from the presence of `state_after` in the response. If
`state_after` is missing, clients MUST behave as if they had not
specified the parameter and update their local state with events
in `state` and `timeline`.
By default, this is `false`.
example: false

View file

@ -3,24 +3,6 @@
"type": "m.push_rules",
"content": {
"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": [],
@ -82,12 +64,14 @@
],
"conditions": [
{
"kind": "contains_display_name"
"kind": "event_property_contains",
"key": "content.m\\.mentions.user_ids",
"value": "@alice:example.com"
}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.contains_display_name"
"rule_id": ".m.rule.is_user_mention"
},
{
"actions": [

View file

@ -13,24 +13,34 @@ description: |-
0. If the room contains no `m.room.power_levels` event, the room's creator has
a power level of 100, and all other users have a power level of 0.
The level required to send a certain event is governed by `events`,
`state_default` and `events_default`. If an event type is specified in
`events`, then the user must have at least the level specified in order to
send that event. If the event type is not supplied, it defaults to
`events_default` for Message Events and `state_default` for State
Events.
Except for membership events and redactions, the level required to
send a certain event is governed purely by `events`, `state_default`
and `events_default`. If an event type is specified in `events`, then
the user must have at least the level specified in order to send that
event. If the event type is not supplied, it defaults to `events_default`
for message events and `state_default` for state events.
If there is no `state_default` in the `m.room.power_levels` event, or
there is no `m.room.power_levels` event, the `state_default` is 50.
If there is no `events_default` in the `m.room.power_levels` event,
or there is no `m.room.power_levels` event, the `events_default` is 0.
The power level required to invite a user to the room, kick a user from the
room, ban a user from the room, or redact an event sent by another user, is
defined by `invite`, `kick`, `ban`, and `redact`, respectively. The levels
for `kick`, `ban` and `redact` default to 50 if they are not specified in the
`m.room.power_levels` event, or if the room contains no `m.room.power_levels`
event. `invite` defaults to 0 in either case.
Membership events are not subject to `events`, `events_default`, or
`state_default`. Instead, the power level required to invite a user
to the room, kick a user from the room, or ban a user from the room
is defined by `invite`, `kick`, and `ban`, respectively. The levels
for `kick` and `ban` default to 50 if they are not specified in the
`m.room.power_levels` event, or if the room contains no
`m.room.power_levels` event. `invite` defaults to 0 in either case.
Other membership values are handled during event authorization. See
the authorization rules in [room versions](/rooms) for further details.
For redactions of a user's own events, the required power level is
determined by the `m.room.redaction` event power level, as per `events`
and `events_default`. The power level required to redact an event sent
by another user is _additionally_ governed by `redact`. The level for
`redact` defaults to 50 if it is not specified in the `m.room.power_levels`
event, or if the room contains no `m.room.power_levels` event.
**Note:**

View file

@ -0,0 +1,19 @@
{{- /*
This is a passthrough render hook (https://gohugo.io/render-hooks/passthrough/).
We use it to send the delimited passthrough element through KaTeX to render maths
in the Olm / Megolm spec.
See: https://gohugo.io/functions/transform/tomath/#step-2
*/ -}}
{{- $opts := dict "output" "htmlAndMathml" "displayMode" (eq .Type "block") }}
{{- with try (transform.ToMath .Inner $opts) }}
{{- with .Err }}
{{- errorf "Unable to render mathematical markup to HTML using the transform.ToMath function. The KaTeX display engine threw the following error: %s: see %s." . $.Position }}
{{- else }}
{{- .Value }}
{{- $.Page.Store.Set "hasMath" true }}
{{- end }}
{{- end -}}

View file

@ -0,0 +1,61 @@
{{/*
Renders a list of API endpoints for the current page, given:
The outer page's Scratch must contain an "api_endpoints" key, which is either
a slice of maps (a list of endpoint metadata dicts) or a map of module name ->
slice of endpoint metadata dicts (representing the API modules and the
endpoints they each contain). Each endpoint dict must contain the following
keys:
* `anchor`: the HTML anchor for the endpoint
* `method`: the HTTP method
* `endpoint`: the endpoint path
* `summary`: a short summary of the endpoint
* `deprecated`: whether the endpoint is deprecated
* `module`: the CS API module name, if any, for grouping purposes. If empty,
the endpoint is considered "base" or "required".
*/}}
{{ $raw := .Scratch.Get "api_endpoints" }}
{{/* Normalize to a slice */}}
{{ $endpoints := slice }}
{{ if reflect.IsSlice $raw }}
{{ $endpoints = $raw }}
{{ else if reflect.IsMap $raw }}
{{ range $raw }}
{{ $endpoints = append $endpoints . }}
{{ end }}
{{ end }}
{{ if gt (len $endpoints) 0 }}
<div class="endpoints-toc mb-4">
<details>
<summary>List of Endpoints</summary>
{{/* Sort by module to group visually */}}
{{ $sorted := sort $endpoints "module" }}
{{ $current := "" }}
{{ range $sorted }}
{{ $mod := .module }}
{{/* Set a title for the base endpoints */}}
{{ if not $mod }}{{ $mod = "Required" }}{{ end }}
{{ if ne $mod $current }}
{{ if $current }}</ul></div>{{ end }}
<div class="endpoint-module">
<div class="endpoint-module-title">{{ $mod }}</div>
<ul class="endpoint-list">
{{ $current = $mod }}
{{ end }}
{{ $key := printf "%s|%s" .method .anchor }}
<li>
<a href="#{{ .anchor }}">
<span class="http-api-method">{{ .method }}</span>
<span class="endpoint-path">{{ .endpoint }}</span>
{{ if .deprecated }}<span class="endpoint-deprecated">(deprecated)</span>{{ end }}
</a>
</li>
{{ end }}
{{ if $current }}</ul></div>{{ end }}
</details>
</div>
{{ end }}

View file

@ -8,3 +8,10 @@
*/}}
{{ $toc := resources.Get "js/toc.js" -}}
<script defer src="{{ $toc.RelPermalink }}"></script>
{{- /* Load the versions script template, run and publish it */ -}}
{{ with resources.Get "js/versions.template.js" }}
{{ with resources.ExecuteAsTemplate "js/versions.js" $ . }}
<script defer src="{{ .RelPermalink }}"></script>
{{ end }}
{{ end }}

View file

@ -0,0 +1,18 @@
{{- /*
A version of the navbar-version-selector.html partial in Docsy,
modified to read the versions from /versions.json.
*/ -}}
{{ $changelog := site.GetPage "changelog" }}
{{ $pages := $changelog.RegularPages.ByDate.Reverse }}
<div class="dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
All Versions
</a>
<ul class="dropdown-menu" id="version-selector">
{{- /* The menu is built by versions.template.js */ -}}
</ul>
</div>

View file

@ -7,6 +7,8 @@
of each value in `paths` to get a complete URL.
* `anchor_base`: an optional prefix for the HTML IDs generated by
this template.
* `page`: the (Hugo) Page object to store endpoint metadata in the Scratch of. Used to build the endpoints TOC.
* `module`: the current CS API module name, if any. Used to group endpoints in the TOC.
This template replaces the old {{*_http_api}} template.
@ -15,6 +17,8 @@
{{ $api_data := index .api_data }}
{{ $base_url := .base_url }}
{{ $anchor_base := .anchor_base }}
{{ $page := .page }}
{{ $module := .module }}
{{ range $path_name, $path_data := $api_data.paths }}
@ -26,28 +30,28 @@
{{ with $path_data.get }}
{{ $operation_params := merge $params (dict "method" "GET" "operation_data" . "anchor_base" $anchor_base) }}
{{ $operation_params := merge $params (dict "method" "GET" "operation_data" . "anchor_base" $anchor_base "page" $page "module" $module) }}
{{ partial "openapi/render-operation" $operation_params }}
{{ end }}
{{ with $path_data.post }}
{{ $operation_params := merge $params (dict "method" "POST" "operation_data" . "anchor_base" $anchor_base) }}
{{ $operation_params := merge $params (dict "method" "POST" "operation_data" . "anchor_base" $anchor_base "page" $page "module" $module) }}
{{ partial "openapi/render-operation" $operation_params }}
{{ end }}
{{ with $path_data.put }}
{{ $operation_params := merge $params (dict "method" "PUT" "operation_data" . "anchor_base" $anchor_base) }}
{{ $operation_params := merge $params (dict "method" "PUT" "operation_data" . "anchor_base" $anchor_base "page" $page "module" $module) }}
{{ partial "openapi/render-operation" $operation_params }}
{{ end }}
{{ with $path_data.delete }}
{{ $operation_params := merge $params (dict "method" "DELETE" "operation_data" . "anchor_base" $anchor_base) }}
{{ $operation_params := merge $params (dict "method" "DELETE" "operation_data" . "anchor_base" $anchor_base "page" $page "module" $module) }}
{{ partial "openapi/render-operation" $operation_params }}
{{ end }}

View file

@ -7,6 +7,8 @@
* `operation_data`: the OpenAPI data for the operation
* `anchor_base`: an optional prefix for the HTML IDs generated by
this template.
* `page`: the (Hugo) Page object to store endpoint metadata in the Scratch of. Used to build the endpoints TOC.
* `module`: the current CS API module name, if any. Used to group endpoints in the TOC.
This template renders the operation as a `<section>` containing:
@ -22,6 +24,8 @@
{{ $method := .method }}
{{ $endpoint := .endpoint }}
{{ $operation_data := .operation_data }}
{{ $page := .page }}
{{ $module := .module }}
{{ $anchor := "" }}
{{ if .anchor_base }}
@ -29,6 +33,27 @@
{{ end }}
{{ $anchor = printf "%s%s%s" $anchor (lower $method) (anchorize $endpoint) }}
{{/* Collect endpoints for the on-page endpoints TOC */}}
{{ if $page }}
{{/* Store each endpoint's metadata in a scratch variable */}}
{{ $entry := dict "anchor" $anchor "method" $method "endpoint" $endpoint "summary" $operation_data.summary "deprecated" $operation_data.deprecated "module" $module }}
{{ if not ($page.Scratch.Get "api_endpoints_seen") }}
{{ $page.Scratch.Set "api_endpoints_seen" dict }}
{{ end }}
{{/* Keep a map of seen endpoints. This is necessary as this partial may be
rendered multiple times for the same endpoint (e.g. in the TOC and
in the main content), leading to duplicates. */}}
{{ $seen := $page.Scratch.Get "api_endpoints_seen" }}
{{ $key := printf "%s|%s" $method $endpoint }}
{{ if not (index $seen $key) }}
{{ if not (reflect.IsSlice ($page.Scratch.Get "api_endpoints")) }}
{{ $page.Scratch.Set "api_endpoints" (slice) }}
{{ end }}
{{ $page.Scratch.Add "api_endpoints" (slice $entry) }}
{{ $page.Scratch.SetInMap "api_endpoints_seen" $key true }}
{{ end }}
{{ end }}
<section class="rendered-data">
<details {{ if not site.Params.ui.rendered_data_collapsed }}open{{ end }}>

View file

@ -0,0 +1,14 @@
{{- /* Shared render for spec pages: title, optional description, endpoints list, body, and last-mod info. */ -}}
<div class="td-content">
<h1>{{ .Title }}</h1>
{{ with .Params.description }}<p class="page-description">{{ . | markdownify }}</p>{{ end }}
{{/*
Render an endpoints table of contents. This is the main difference
between our templates (which call the spec-content partial) and the default
Docsy template.
*/}}
{{ partial "endpoints-toc.html" . }}
{{ .Content }}
</div>

View file

@ -3,14 +3,39 @@
This template is used to render a Client-Server API Module. Modules are defined
alongside the `_index.md` for the CS API.
The `name` parameter is the file name without extension.
The following parameters are expected:
* `filename` the name of the module file to render, without extension (i.e. `spaces`).
* `name` the display name of the module (i.e. `Spaces`).
*/}}
{{ $name := .Params.name }}
{{ $filename := .Params.filename }}
{{ with .Site.GetPage "client-server-api/modules" }}
{{ with .Resources.GetMatch (printf "%s%s" $name ".md") }}
{{ with .Resources.GetMatch (printf "%s%s" $filename ".md") }}
{{/* Preserve previous scratch values so nested modules don't leak */}}
{{ $prevPage := .Scratch.Get "endpoint_page" }}
{{ $prevModule := .Scratch.Get "endpoint_module" }}
{{/* Allow endpoints rendered in the module to accumulate on the parent page */}}
{{ .Scratch.Set "endpoint_page" $.Page }}
{{/* Name the module for grouping in the endpoints list */}}
{{ .Scratch.Set "endpoint_module" $name }}
{{ .RenderShortcodes }}
{{/* Restore previous scratch values */}}
{{ if $prevPage }}
{{ .Scratch.Set "endpoint_page" $prevPage }}
{{ else }}
{{ .Scratch.Delete "endpoint_page" }}
{{ end }}
{{ if $prevModule }}
{{ .Scratch.Set "endpoint_module" $prevModule }}
{{ else }}
{{ .Scratch.Delete "endpoint_module" }}
{{ end }}
{{ end }}
{{ end }}

View file

@ -23,6 +23,20 @@
{{ $api := .Params.api}}
{{ $anchor_base := .Params.anchor_base}}
{{/*
Figure out which Page object to pass to the `openapi/render-api` partial.
Either our own, or one stored under `endpoint_page` in the Scratch, if one
exists.
*/}}
{{ $target_page := .Page }}
{{ with .Page.Scratch.Get "endpoint_page" }}
{{ $target_page = . }}
{{ end }}
{{ $module_name := .Page.Scratch.Get "endpoint_module" }}
{{ $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 $api) "/" }}
@ -30,4 +44,4 @@
{{ $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) }}
{{ partial "openapi/render-api" (dict "api_data" $api_data "base_url" $base_url "anchor_base" $anchor_base "page" $target_page "module" $module_name) }}

View file

@ -1,4 +0,0 @@
<div class="td-content">
<h1>{{ .Title }}</h1>
{{ .Content }}
</div>

View file

@ -5,6 +5,25 @@
*/}}
{{/* Generate a static file versions.json that can be used to populate the version picker */}}
{{ if .IsHome }}
{{- /* Load all changelog subpages, sorted by release date */ -}}
{{ $changelog := site.GetPage "changelog" }}
{{ $pages := $changelog.RegularPages.ByDate.Reverse }}
{{- /* Collect proper versions and build metadata dicts */ -}}
{{ $versions := slice }}
{{ range $pages }}
{{ if findRE `^v[0-9]+\.[0-9]+$` .Params.linkTitle }}
{{ $versions = $versions | append (dict "name" .Params.linkTitle "date" .Params.date ) }}
{{ end }}
{{ end }}
{{- /* Generate the JSON */ -}}
{{ $json := jsonify $versions }}
{{ $noop := (resources.FromString "/versions.json" $json).Permalink }}
{{ end }}
<!doctype html>
<html itemscope itemtype="http://schema.org/WebPage"
{{- with .Site.Language.LanguageDirection }} dir="{{ . }}" {{- end -}}
@ -12,6 +31,10 @@
class="no-js">
<head>
{{ partial "head.html" . }}
{{ if .Page.Store.Get "hasMath" }}
<link href="{{ relURL "css/katex.min.css" }}" rel="preload" as="style">
<link href="{{ relURL "css/katex.min.css" }}" rel="stylesheet">
{{ end }}
</head>
<body class="td-{{ .Kind }}{{ with .Page.Params.body_class }} {{ . }}{{ end }}">
<header>

View file

@ -1,13 +1,19 @@
{{/*
A simplified version of the list.html partial in Docsy.
Override the `layouts/docs/list.html` template from Docsy. While this template
is equivalent to `single.html`, it's necessary to override both templates to
avoid falling back to the default Docsy templates.
https://gohugo.io/templates/types/#list
We use this list template to render the Client-Server API spec page and each
of its modules.
The contents of the "main" block below are inserted into the `./baseof.html`
base template.
*/}}
{{ define "main" }}
<div class="td-content">
<h1>{{ .Title }}</h1>
{{ with .Params.description }}<div class="lead">{{ . | markdownify }}</div>{{ end }}
{{ .Content }}
</div>
{{ partial "spec-content.html" . }}
{{ end }}

19
layouts/docs/single.html Normal file
View file

@ -0,0 +1,19 @@
{{/*
Override the `layouts/docs/single.html` template from Docsy. While this template
is equivalent to `list.html`, it's necessary to override both templates to
avoid falling back to the default Docsy templates.
https://gohugo.io/templates/types/#single
We use this single template to render the all API spec pages *except* the
Client-Server API. The Client-Server API spec page contains modules, and thus
is handled separately, via the `layouts/docs/list.html` template.
The contents of the "main" block below are inserted into the `./baseof.html`
base template.
*/}}
{{ define "main" }}
{{ partial "spec-content.html" . }}
{{ end }}

View file

@ -16,6 +16,9 @@ const purgecss = require('@fullhuman/postcss-purgecss')({
extensions: ["json"],
},
],
// As these classes are only applied by JavaScript, PurgeCSS doesn't see them
// in the source code and removes them unless we explicitly tell it not to.
safelist: ['version-picker-selected', 'version-picker-latest']
});
module.exports = {

View file

@ -9,3 +9,6 @@ rules:
no-path-trailing-slash: off
operation-2xx-response: off
spec-strict-refs: error
# $ref in examples are not spec-compliant, yet we find them useful. Disable this rule
# and instead check example schema using `check-event-schema-examples.py`
no-invalid-schema-examples: off

View file

@ -0,0 +1,41 @@
#!/bin/bash
#
# Download the KaTeX fonts and CSS, and copy them into `static`.
set -e
root=$(dirname "$0")/..
# Check that the caller supplied a version.
version=$1
if [[ -z $1 || $1 = "-h" || $1 = "--help" ]]; then
>&2 echo "Usage: download-katex-assets.sh VERSION (e.g. v0.16.23)"
>&2 echo
>&2 echo "Downloads KaTeX fonts and CSS from the specified release"
>&2 echo "on GitHub and puts the files into static/."
exit 1
fi
# Create a temporary directory and register a handler to clean it up on exit.
tmp_dir=$(mktemp -d)
clean_up () {
rm -rf "$tmp_dir"
}
trap clean_up EXIT
# Fetch the release archive.
archive=$tmp_dir/katex.tar.gz
url=https://github.com/KaTeX/KaTeX/releases/download/$version/katex.tar.gz
echo "GET $url"
curl -L --output "$archive" "$url"
# Unpack the archive.
tar -xzvf "$archive" -C "$tmp_dir"
# Move the CSS file into place.
install -vm644 "$tmp_dir/katex/katex.min.css" "$root/static/css/katex.min.css"
# Remove any existing fonts and move the new ones into place.
rm -rvf "$root"/static/css/fonts/KaTeX*
while IFS= read -r -d '' file; do
install -vm644 "$file" "$root/static/css/fonts"
done < <(find "$tmp_dir/katex/fonts" -maxdepth 1 -name "KaTeX*.woff2" -print0)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

1
static/css/katex.min.css vendored Normal file

File diff suppressed because one or more lines are too long