From b7577ea2371bd7b97b7fdf26c1cca9721bbd9621 Mon Sep 17 00:00:00 2001 From: Valentin Deniaud Date: Sat, 14 Jul 2018 14:22:36 +0200 Subject: [PATCH 01/26] document encrypted attachments Fix #461. --- .../examples/m.room.message.encrypted_file | 55 +++++++++++ .../schema/m.room.message.encrypted_file | 95 +++++++++++++++++++ .../modules/end_to_end_encryption.rst | 35 +++++++ 3 files changed, 185 insertions(+) create mode 100644 event-schemas/examples/m.room.message.encrypted_file create mode 100644 event-schemas/schema/m.room.message.encrypted_file diff --git a/event-schemas/examples/m.room.message.encrypted_file b/event-schemas/examples/m.room.message.encrypted_file new file mode 100644 index 00000000..1b157922 --- /dev/null +++ b/event-schemas/examples/m.room.message.encrypted_file @@ -0,0 +1,55 @@ +{ + "age": 146, + "content": { + "body": "something-important.doc", + "filename": "something-important.doc", + "file": { + "url": "mxc://localhost/FHyPlCeYUSFFxlgbQYZmoEoe", + "mimetype": "application/msword", + "v": "v2", + "key": { + "alg": "A256CTR", + "ext": true, + "k": "aWF6-32KGYaC3A_FEUCk1Bt0JA37zP0wrStgmdCaW-0", + "key_ops": ["encrypt","decrypt"], + "kty": "oct" + }, + "iv": "w+sE15fzSc0AAAAAAAAAAA", + "hashes": { + "sha256": "fdSLu/YkRx3Wyh3KQabP3rd6+SFiKg5lsJZQHtkSAYA" + } + }, + "info": { + "mimetype": "application/msword", + "size": 46144, + "thumbnail_file": { + "hashes": { + "sha256": "/NogKqW5bz/m8xHgFiH5haFGjCNVmUIPLzfvOhHdrxY" + }, + "iv": "U+k7PfwLr6UAAAAAAAAAAA", + "key": { + "alg": "A256CTR", + "ext": true, + "k": "RMyd6zhlbifsACM1DXkCbioZ2u0SywGljTH8JmGcylg", + "key_ops": ["encrypt", "decrypt"], + "kty": "oct" + }, + "mimetype": "image/jpeg", + "url": "mxc://localhost/pmVJxyxGlmxHposwVSlOaEOv", + "v": "v2" + }, + "thumbnail_info": { + "h": 768, + "mimetype": "image/jpeg", + "size": 211009, + "w": 432 + } + }, + "msgtype": "m.file" + }, + "event_id": "$143273582443PhrSn:localhost", + "origin_server_ts": 1432735824653, + "room_id": "!jEsUZKDJdhlrceRyVU:localhost", + "type": "m.room.message", + "sender": "@example:localhost" +} diff --git a/event-schemas/schema/m.room.message.encrypted_file b/event-schemas/schema/m.room.message.encrypted_file new file mode 100644 index 00000000..b1f5d1f4 --- /dev/null +++ b/event-schemas/schema/m.room.message.encrypted_file @@ -0,0 +1,95 @@ +--- +allOf: + - $ref: core-event-schema/room_event.yaml +description: |- + This message represents an encrypted generic file, corresponding to a + plaintext ``m.file`` message. ``m.image``, ``m.video`` and ``m.audio`` can be + sent encrypted using the same structure. +properties: + content: + properties: + body: + description: |- + A human-readable description of the file. This is recommended to be + the filename of the original upload. + type: string + filename: + description: The original filename of the uploaded file. + type: string + info: + description: Information about the file referred to in ``url``. + properties: + mimetype: + description: The mimetype of the file e.g. ``application/msword``. + type: string + size: + description: The size of the file in bytes. + type: integer + thumbnail_file: + description: The URL to the thumbnail of the file. + title: EncryptedFile + type: object + thumbnail_info: + allOf: + - $ref: core-event-schema/msgtype_infos/thumbnail_info.yaml + description: Metadata about the image referred to in ``thumbnail_url``. + title: FileInfo + type: object + msgtype: + enum: + - m.file + type: string + file: + description: Information needed to decrypt the file. + properties: + url: + description: The URL to the file. + type: string + key: + description: A JSON web key object (as defined in RFC7517 LINK). + type: object + title: JWK + properties: + kty: + description: Key type. Must be ``oct``. + type: string + key_ops: + description: |- + Key operations. Must at least contain ``encrypt`` and ``decrypt``. + type: array + items: + type: string + alg: + description: Algorithm. Must be ``A256CTR``. + type: string + k: + description: The key, encoded as urlsafe unpadded base64. + type: string + ext: + description: Extractable. Must be ``true``.(W3C link) + type: boolean + iv: + description: The Initialisation Vector used by AES-CTR. + type: string + hashes: + description: A map from an algorithm name to a hash of the ciphertext. + type: object + additionalProperties: + type: string + v: + description: Version of the encrypted attachments protocol. + type: string + title: EncryptedFile + type: object + required: + - msgtype + - body + - file + - filename + type: object + type: + enum: + - m.room.message + type: string +title: EncryptedFileMessage +type: object diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index fa461cc2..c6a8f28f 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -224,6 +224,39 @@ process: .. |device_lists| replace:: ``device_lists`` .. _`device_lists`: `device_lists_sync`_ + +Sending encrypted attachments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When encryption is enabled in a room, files should be uploaded encrypted on +the homeserver. + +In order to achieve this, a client should generate a single-use 256 bits AES key. +Then, it should encrypt the file using AES-CTR. The counter should be 64 bits long, +starting at 0 and prefixed by a random 64 bits Initialization Vector (IV), which +together form a 128 bits unique counter block. + +.. Warning:: + An IV must never be used multiple times with the same key. This implies that if there + are multiple files to encrypt in the same message, typically an image and its thumbnail, + the key may be reused, but not the IV. + +Then, the encrypted file can be uploaded to the homeserver. +The key and the IV must be shared along with the resulting ``mxc://`` in order to allow +recipients to decrypt the file. As the event containing those will be Megolm encrypted, +the server will never have access to the decrypted file. + +A hash of the ciphertext must also be included, in order to prevent the homeserver from +changing the file content. + +A client should send those data as a ``m.room.message``. The structure is similar to +a ``m.file`` message or equivalent. The two differing keys are ``url`` and +``thumbnail_url``, which are replaced respectively by ``file`` and ``thumbnail_file``, +containing an ``EncryptedFile`` object as specified below. The key is sent using +the `JSON Web Key`_ format, with a `W3C extension`_. + +{{m_room_message_encrypted_file_event}} + Claiming one-time keys ~~~~~~~~~~~~~~~~~~~~~~ @@ -548,6 +581,8 @@ Example response: .. _curve25519: https://cr.yp.to/ecdh.html .. _`Olm specification`: http://matrix.org/docs/spec/olm.html .. _`Megolm specification`: http://matrix.org/docs/spec/megolm.html +.. _`JSON Web Key`: https://tools.ietf.org/html/rfc7517#appendix-A.3 +.. _`W3C extension`: https://w3c.github.io/webcrypto/#iana-section-jwk .. _`Signing JSON`: ../appendices.html#signing-json From d6f5d590f8caaa76ba7c3dc642a2386431189886 Mon Sep 17 00:00:00 2001 From: Valentin Deniaud Date: Tue, 21 Aug 2018 21:54:37 +0200 Subject: [PATCH 02/26] add encrypted attachments changelog --- changelogs/client_server/newsfragments/1420.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/client_server/newsfragments/1420.feature diff --git a/changelogs/client_server/newsfragments/1420.feature b/changelogs/client_server/newsfragments/1420.feature new file mode 100644 index 00000000..f7cf687d --- /dev/null +++ b/changelogs/client_server/newsfragments/1420.feature @@ -0,0 +1 @@ +Encrypt file attachments From 28ced3b0a4629b8943aa8e4b0f13e719dc67c70e Mon Sep 17 00:00:00 2001 From: Valentin Deniaud Date: Tue, 28 Aug 2018 15:04:40 +0200 Subject: [PATCH 03/26] fixup! document encrypted attachments --- .../schema/m.room.message.encrypted_file | 15 ++++++--- .../modules/end_to_end_encryption.rst | 32 ++++++++++--------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/event-schemas/schema/m.room.message.encrypted_file b/event-schemas/schema/m.room.message.encrypted_file index b1f5d1f4..4f9229b7 100644 --- a/event-schemas/schema/m.room.message.encrypted_file +++ b/event-schemas/schema/m.room.message.encrypted_file @@ -17,7 +17,7 @@ properties: description: The original filename of the uploaded file. type: string info: - description: Information about the file referred to in ``url``. + description: Information about the file referred to in ``file``. properties: mimetype: description: The mimetype of the file e.g. ``application/msword``. @@ -46,7 +46,7 @@ properties: description: The URL to the file. type: string key: - description: A JSON web key object (as defined in RFC7517 LINK). + description: A `JSON web key`_ object. type: object title: JWK properties: @@ -66,19 +66,24 @@ properties: description: The key, encoded as urlsafe unpadded base64. type: string ext: - description: Extractable. Must be ``true``.(W3C link) + description: Extractable. Must be ``true``. This is a `W3C extension`_. type: boolean iv: - description: The Initialisation Vector used by AES-CTR. + description: |- + The Initialisation Vector used by AES-CTR, encoded as unpadded + base64. type: string hashes: - description: A map from an algorithm name to a hash of the ciphertext. + description: |- + A map from an algorithm name to a hash of the ciphertext, encoded + as unpadded base64. Clients should support the SHA-256 hash. type: object additionalProperties: type: string v: description: Version of the encrypted attachments protocol. type: string + enum: ["v2"] title: EncryptedFile type: object required: diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index c6a8f28f..e5bc0cb0 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -231,29 +231,31 @@ Sending encrypted attachments When encryption is enabled in a room, files should be uploaded encrypted on the homeserver. -In order to achieve this, a client should generate a single-use 256 bits AES key. -Then, it should encrypt the file using AES-CTR. The counter should be 64 bits long, -starting at 0 and prefixed by a random 64 bits Initialization Vector (IV), which -together form a 128 bits unique counter block. +In order to achieve this, a client should generate a single-use 256-bit AES +key, and encrypt the file using AES-CTR. The counter should be 64-bit long, +starting at 0 and prefixed by a random 64-bit Initialization Vector (IV), which +together form a 128-bit unique counter block. .. Warning:: - An IV must never be used multiple times with the same key. This implies that if there - are multiple files to encrypt in the same message, typically an image and its thumbnail, - the key may be reused, but not the IV. + An IV must never be used multiple times with the same key. This implies that + if there are multiple files to encrypt in the same message, typically an + image and its thumbnail, the files must not share both the same key and IV. Then, the encrypted file can be uploaded to the homeserver. -The key and the IV must be shared along with the resulting ``mxc://`` in order to allow -recipients to decrypt the file. As the event containing those will be Megolm encrypted, -the server will never have access to the decrypted file. +The key and the IV must be included in the room event along with the resulting +``mxc://`` in order to allow recipients to decrypt the file. As the event +containing those will be Megolm encrypted, the server will never have access to +the decrypted file. A hash of the ciphertext must also be included, in order to prevent the homeserver from changing the file content. -A client should send those data as a ``m.room.message``. The structure is similar to -a ``m.file`` message or equivalent. The two differing keys are ``url`` and -``thumbnail_url``, which are replaced respectively by ``file`` and ``thumbnail_file``, -containing an ``EncryptedFile`` object as specified below. The key is sent using -the `JSON Web Key`_ format, with a `W3C extension`_. +A client should send the data as a ``m.room.message`` event, using either +``m.file`` as the msgtype, or the appropriate msgtype for the file type. The +structure is similar to an unencrypted file message, except for two differing +keys: ``url`` and ``thumbnail_url`` are replaced respectively by ``file`` and +``thumbnail_file``, containing an ``EncryptedFile`` object as specified below. +The key is sent using the `JSON Web Key`_ format, with a `W3C extension`_. {{m_room_message_encrypted_file_event}} From 6e0fe705004e4e50638f1059be167f572b893a22 Mon Sep 17 00:00:00 2001 From: Ben Parsons Date: Wed, 29 Aug 2018 16:38:59 +0100 Subject: [PATCH 04/26] make spec tables prettier --- scripts/css/basic.css | 23 +++++++++++++++++++ .../templates/common-event-fields.tmpl | 3 +-- .../matrix_templates/templates/events.tmpl | 1 - .../matrix_templates/templates/http-api.tmpl | 8 +++---- .../matrix_templates/templates/msgtypes.tmpl | 9 ++++++-- .../templates/schema-definition.tmpl | 2 +- .../matrix_templates/templates/tables.tmpl | 18 +++++++++++---- 7 files changed, 49 insertions(+), 15 deletions(-) diff --git a/scripts/css/basic.css b/scripts/css/basic.css index 6411570e..1b5a4b61 100644 --- a/scripts/css/basic.css +++ b/scripts/css/basic.css @@ -318,6 +318,29 @@ table.citation td { border-bottom: none; } +table.colwidths-auto caption { + font-family: monospace; + font-size: x-large; + padding: 2px; +} + +table.colwidths-auto { + width:100%; + margin-top: 20px; +} + +table.colwidths-auto tr td:nth-child(1) { + width: 15%; +} + +table.colwidths-auto tr td:nth-child(2) { + width: 15%; +} + +table.colwidths-auto tr td:nth-child(3) { + width: 70%; +} + /* -- other body styles ----------------------------------------------------- */ ol.arabic { diff --git a/scripts/templating/matrix_templates/templates/common-event-fields.tmpl b/scripts/templating/matrix_templates/templates/common-event-fields.tmpl index 9d0ddac3..b69fb79c 100644 --- a/scripts/templating/matrix_templates/templates/common-event-fields.tmpl +++ b/scripts/templating/matrix_templates/templates/common-event-fields.tmpl @@ -6,8 +6,7 @@ {{common_event.desc}} {% for table in common_event.tables %} -{{"``"+table.title+"``" if table.title else "" }} -{{ tables.paramtable(table.rows, ["Key", "Type", "Description"]) }} +{{ tables.paramtable(table.rows, [(table.title or "") ~ " Key", "Type", "Description"]) }} {% endfor %} diff --git a/scripts/templating/matrix_templates/templates/events.tmpl b/scripts/templating/matrix_templates/templates/events.tmpl index ded33859..e5ec899f 100644 --- a/scripts/templating/matrix_templates/templates/events.tmpl +++ b/scripts/templating/matrix_templates/templates/events.tmpl @@ -12,7 +12,6 @@ {{event.desc}} {% for table in event.content_fields %} -{{"``"+table.title+"``" if table.title else "" }} {{ tables.paramtable(table.rows, [(table.title or "Content") ~ " Key", "Type", "Description"]) }} diff --git a/scripts/templating/matrix_templates/templates/http-api.tmpl b/scripts/templating/matrix_templates/templates/http-api.tmpl index 461a0b58..db70da42 100644 --- a/scripts/templating/matrix_templates/templates/http-api.tmpl +++ b/scripts/templating/matrix_templates/templates/http-api.tmpl @@ -18,8 +18,8 @@ Request format: {{ tables.split_paramtable(endpoint.req_param_by_loc) }} {% if (endpoint.req_body_tables) %} {% for table in endpoint.req_body_tables -%} -{{"``"+table.title+"``" if table.title else "" }} -{{ tables.paramtable(table.rows) }} +{{ tables.paramtable(table.rows, [(table.title or "") ~ " Parameter", "Type", "Description"] ) }} + {% endfor -%} {% endif -%} @@ -37,9 +37,9 @@ Response headers: Response format: {% for table in endpoint.res_tables -%} -{{"``"+table.title+"``" if table.title else "" }} -{{ tables.paramtable(table.rows) }} +{{ tables.paramtable(table.rows, [(table.title or "") ~ " Parameter", "Type", "Description"] ) }} + {% endfor %} {% endif -%} diff --git a/scripts/templating/matrix_templates/templates/msgtypes.tmpl b/scripts/templating/matrix_templates/templates/msgtypes.tmpl index 87cf4a19..dfcf2e9d 100644 --- a/scripts/templating/matrix_templates/templates/msgtypes.tmpl +++ b/scripts/templating/matrix_templates/templates/msgtypes.tmpl @@ -4,9 +4,14 @@ {{(4 + event.msgtype | length) * title_kind}} {{event.desc | wrap(80)}} {% for table in event.content_fields -%} -{{"``"+table.title+"``" if table.title else "" }} -{{ tables.paramtable(table.rows, [(table.title or "Content") ~ " Key", "Type", "Description"]) }} +{% if table.title -%} +{% set tabletitle = table.title -%} +{% else -%} +{% set tabletitle = "" -%} +{% endif -%} + +{{ tables.paramtable(table.rows, [(table.title or "Content") ~ " Key", "Type", "Description"] ) }} {% endfor %} Example: diff --git a/scripts/templating/matrix_templates/templates/schema-definition.tmpl b/scripts/templating/matrix_templates/templates/schema-definition.tmpl index e2be12e8..0c4be577 100644 --- a/scripts/templating/matrix_templates/templates/schema-definition.tmpl +++ b/scripts/templating/matrix_templates/templates/schema-definition.tmpl @@ -8,7 +8,7 @@ {% endif %} {% for table in definition.tables -%} -{{"``"+table.title+"``" if table.title else "" }} +{{"``7777"+table.title+"``" if table.title else "" }} {{ tables.paramtable(table.rows) }} {% endfor %} diff --git a/scripts/templating/matrix_templates/templates/tables.tmpl b/scripts/templating/matrix_templates/templates/tables.tmpl index 6d6e4f8e..13ac08c8 100644 --- a/scripts/templating/matrix_templates/templates/tables.tmpl +++ b/scripts/templating/matrix_templates/templates/tables.tmpl @@ -36,6 +36,14 @@ {% set fieldwidths = (([titlerow] + flatrows) | fieldwidths(rowkeys[0:-1], [10, 10])) + [50] -%} +{% set caption = titlerow['key'] | replace (' Key', '') | replace ('Parameter', '') -%} +{% if caption == 'Content' -%} +{% set caption = '' -%} +{% endif -%} + +{{".. table:: "}}{{ caption }} +{{" :widths: auto"}} +{{""}} {{ tableheader(fieldwidths) }} {{ tablerow(fieldwidths, titlerow, rowkeys) }} {{ tableheader(fieldwidths) }} @@ -59,7 +67,7 @@ # Write a table header row, for the given column widths #} {% macro tableheader(widths) -%} -{% for arg in widths -%} +{{" "}}{% for arg in widths -%} {{"="*arg}} {% endfor -%} {% endmacro %} @@ -71,7 +79,7 @@ # attributes of 'row' to look up for values to put in the columns. #} {% macro tablerow(widths, row, keys) -%} -{% for key in keys -%} +{{" "}}{% for key in keys -%} {% set value=row[key] -%} {% if not loop.last -%} {# the first few columns need space after them -#} @@ -81,7 +89,7 @@ the preceding columns, plus the number of preceding columns (for the separators)) -#} {{ value | wrap(widths[loop.index0]) | - indent_block(widths[0:-1]|sum + loop.index0) -}} + indent_block(widths[0:-1]|sum + loop.index0 + 2) -}} {% endif -%} {% endfor -%} {% endmacro %} @@ -93,10 +101,10 @@ # write a tablespan row. This is a single value which spans the entire table. #} {% macro tablespan(widths, value) -%} -{{value}} +{{" "}}{{value}} {# we write a trailing space to stop the separator being misinterpreted # as a header line. -#} -{{"-"*(widths|sum + widths|length -1)}} {% endmacro %} +{{" "}}{{"-"*(widths|sum + widths|length -1)}} {% endmacro %} From 989b50a1a09e854f3cbe3dda62686e575205912e Mon Sep 17 00:00:00 2001 From: Ben Parsons Date: Wed, 29 Aug 2018 16:40:26 +0100 Subject: [PATCH 05/26] remove debug string --- .../matrix_templates/templates/schema-definition.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/templating/matrix_templates/templates/schema-definition.tmpl b/scripts/templating/matrix_templates/templates/schema-definition.tmpl index 0c4be577..e2be12e8 100644 --- a/scripts/templating/matrix_templates/templates/schema-definition.tmpl +++ b/scripts/templating/matrix_templates/templates/schema-definition.tmpl @@ -8,7 +8,7 @@ {% endif %} {% for table in definition.tables -%} -{{"``7777"+table.title+"``" if table.title else "" }} +{{"``"+table.title+"``" if table.title else "" }} {{ tables.paramtable(table.rows) }} {% endfor %} From 380a53ecbababf086104443babcc5a87bd6100e1 Mon Sep 17 00:00:00 2001 From: Ben Parsons Date: Wed, 29 Aug 2018 17:18:37 +0100 Subject: [PATCH 06/26] adjust caption -> smaller, left align --- scripts/css/basic.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/css/basic.css b/scripts/css/basic.css index 1b5a4b61..ca21a859 100644 --- a/scripts/css/basic.css +++ b/scripts/css/basic.css @@ -320,8 +320,9 @@ table.citation td { table.colwidths-auto caption { font-family: monospace; - font-size: x-large; + font-size: large; padding: 2px; + text-align: left; } table.colwidths-auto { From e227095fb49a413255748fb267f8f2c8e3642207 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 29 Aug 2018 17:42:44 -0600 Subject: [PATCH 07/26] Add rich replies Fixes https://github.com/matrix-org/matrix-doc/issues/1234 The notable parts of this are: * The titles go to insane levels. Rich replies are fairly complex and need some splitting apart to be understandable. * The allowed HTML tags now have an exception for `` Please note that the event example is intended to be fixed by a PR that fixes all event examples. --- specification/modules/instant_messaging.rst | 171 ++++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/specification/modules/instant_messaging.rst b/specification/modules/instant_messaging.rst index 079a4801..93a1f37b 100644 --- a/specification/modules/instant_messaging.rst +++ b/specification/modules/instant_messaging.rst @@ -106,6 +106,13 @@ of tags they can render, falling back to other representations of the tags where For example, a client may not be able to render tables correctly and instead could fall back to rendering tab-delimited text. +A special tag, ``mx-reply``, may appear on rich replies (described below) and should be +allowed if, and only if, the tag appears as the very first tag in the ``formatted_body``. +The tag cannot be nested and cannot be located after another tag in the tree. Because the +tag contains HTML, an ``mx-reply`` is expected to have a partner closing tag and should +be treated similar to a ``div``. Clients that support rich replies will end up stripping +the tag and its contents and therefore may wish to exclude the tag entirely. + .. Note:: A future iteration of the specification will support more powerful and extensible message formatting options, such as the proposal `MSC1225 `_. @@ -335,6 +342,170 @@ change unexpectedly. an English-language implementation on them all? See https://matrix.org/jira/browse/SPEC-425. + +Forming relationships between events +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In some cases, events may wish to reference other events. This could be to form +a thread of messages for the user to follow along with, or to provide more context +as to what a particular event is describing. Currently, the only kind of relation +defined is a "rich reply" where a user may reference another message to create a +thread-like conversation. + +Relationships are defined under an ``m.relates_to`` key in the event's ``content``. +If the event is of the type ``m.room.encrypted``, the ``m.relates_to`` key MUST NOT +be covered by the encryption and instead be put alongside the encryption information +held in the ``content``. + +Rich replies +++++++++++++ + +Users may wish to reference another message when forming their own message, and +clients may wish to better embed the referenced message for the user to have a +better context for the conversation being had. This sort of embedding another +message in a message is known as a "rich reply", or occasionally just a "reply". + +Rich replies may reference another event which also has a rich reply, infinitely. +A rich reply is formed through use of an ``m.relates_to`` relation for ``m.in_reply_to`` +where a single key, ``event_id``, is used to reference the event being replied to. +The referenced event ID MUST belong to the same room where the reply is being sent. +Rich replies can only be constructed in the form of ``m.room.message`` events with +a ``msgtype`` of ``m.text`` or ``m.notice``. Due to the fallback requirements, rich +replies cannot be constructed for types of ``m.emote``, ``m.file``, etc. Rich replies +may reference any other ``m.room.message`` event, however. + +Fallbacks and event representation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some clients may not have support for rich replies and therefore need a fallback +to use instead. Clients that do not support rich replies should render the event +as if rich replies were not special. + +Clients that do support rich replies MUST provide the fallback format on replies, +and MUST strip the fallback before rendering the reply. Rich replies MUST supply +a ``format`` of ``org.matrix.custom.html`` and therefore a ``formatted_body`` +alongside the ``body`` and appropriate ``msgtype``. The specific fall back text +is different for each ``msgtype``, however the general format for the ``body`` is: + +.. code-block:: text + + > <@alice:example.org> This is the original body + + This is where the reply goes + + +The ``formatted_body`` ends up using the following template: + +.. code-block:: html + + +
+ In reply to + @alice:example.org +
+ +
+
+ This is where the reply goes. + + +If the related event does not have a ``formatted_body``, the event's ``body`` should +be considered after encoding any HTML special characters. Note that the ``href`` in +both of the anchors use a `matrix.to URI <../appendices.html#matrix-to-navigation>`_. + +Stripping the fallback +`````````````````````` + +Clients which support rich replies MUST strip the fallback from the event before +rendering the event. This is because the text provided in the fallback cannot be +trusted to be an accurate representation of the event. After removing the fallback, +clients are recommended to represent the event referenced by ``m.in_reply_to`` +similar to the fallback's representation, although clients do have creative freedom +for their user interface. Clients should prefer the ``formatted_body`` over the +``body``, just like with other ``m.room.message`` events. + +To strip the fallback on the ``body``, the client should iterate over each line of +the string, removing any lines that start with the fallback prefix ("> ", +including the space, without quotes) and stopping when a line is encountered without +the prefix. This prefix is known as the "fallback prefix sequence". + +To strip the fallback on the ``formatted_body``, the client should remove the +entirety of the ``mx-reply`` tag. + +Fallback for ``m.text``, ``m.notice``, and unrecognised message types +````````````````````````````````````````````````````````````````````` + +Using the prefix sequence, the first line of the related event's ``body`` should +be prefixed with the user's ID, followed by each line being prefixed with the fallback +prefix sequence. For example:: + + > <@alice:example.org> This is the first line + > This is the second line + + This is the reply + + +The ``formatted_body`` uses the template defined earlier in this section. + +Fallback for ``m.emote`` +```````````````````````` + +Similar to the fallback for ``m.text``, each line gets prefixed with the fallback +prefix sequence. However an asterisk should be inserted before the user's ID, like +so:: + + > * <@alice:example.org> feels like today is going to be a great day + + This is the reply + + +The ``formatted_body`` has a subtle difference for the template where the asterisk +is also inserted ahead of the user's ID: + +.. code-block:: html + + +
+ In reply to + * @alice:example.org +
+ +
+
+ This is where the reply goes. + + +Fallback for ``m.image``, ``m.video``, ``m.audio``, and ``m.file`` +`````````````````````````````````````````````````````````````````` + +The related event's ``body`` would be a file name, which may not be very descriptive. +The related event should additionally not have a ``format`` or ``formatted_body`` +in the ``content`` - if the event does, it should be ignored. Because the filename +alone may not be descriptive, the related event's ``body`` should be considered +to be ``"sent a file."`` such that the output looks similar to the following:: + + > <@alice:example.org> sent a file. + + This is the reply + + +.. code-block:: html + + +
+ In reply to + @alice:example.org +
+ sent a file. +
+
+ This is where the reply goes. + + +For ``m.image``, the text should be ``"sent an image."``. For ``m.video``, the text +should be ``"sent a video."``. For ``m.audio``, the text should be ``"sent an audio file"``. + + Server behaviour ---------------- From 38bb222461a8dc394789411ad6fc192c22bedac0 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 29 Aug 2018 23:00:21 -0600 Subject: [PATCH 08/26] Changelog --- changelogs/client_server/newsfragments/1617.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/client_server/newsfragments/1617.feature diff --git a/changelogs/client_server/newsfragments/1617.feature b/changelogs/client_server/newsfragments/1617.feature new file mode 100644 index 00000000..b2169dd5 --- /dev/null +++ b/changelogs/client_server/newsfragments/1617.feature @@ -0,0 +1 @@ +Add "rich replies" - a way for users to better represent the conversation thread they are referencing in their messages. From 9e1d6d74901735a78b5725756521a52383028dd5 Mon Sep 17 00:00:00 2001 From: Ben Parsons Date: Thu, 30 Aug 2018 17:01:27 +0100 Subject: [PATCH 09/26] sanitise caption handling --- .../templates/common-event-fields.tmpl | 2 +- .../templating/matrix_templates/templates/events.tmpl | 2 +- .../matrix_templates/templates/http-api.tmpl | 4 ++-- .../matrix_templates/templates/msgtypes.tmpl | 8 +------- .../templating/matrix_templates/templates/tables.tmpl | 11 +++-------- 5 files changed, 8 insertions(+), 19 deletions(-) diff --git a/scripts/templating/matrix_templates/templates/common-event-fields.tmpl b/scripts/templating/matrix_templates/templates/common-event-fields.tmpl index b69fb79c..f62f59ba 100644 --- a/scripts/templating/matrix_templates/templates/common-event-fields.tmpl +++ b/scripts/templating/matrix_templates/templates/common-event-fields.tmpl @@ -7,6 +7,6 @@ {% for table in common_event.tables %} -{{ tables.paramtable(table.rows, [(table.title or "") ~ " Key", "Type", "Description"]) }} +{{ tables.paramtable(table.rows, ["Key", "Type", "Description"], (table.title or "")) }} {% endfor %} diff --git a/scripts/templating/matrix_templates/templates/events.tmpl b/scripts/templating/matrix_templates/templates/events.tmpl index e5ec899f..679aee5b 100644 --- a/scripts/templating/matrix_templates/templates/events.tmpl +++ b/scripts/templating/matrix_templates/templates/events.tmpl @@ -13,7 +13,7 @@ {% for table in event.content_fields %} -{{ tables.paramtable(table.rows, [(table.title or "Content") ~ " Key", "Type", "Description"]) }} +{{ tables.paramtable(table.rows, [(table.title or "Content") ~ " Key", "Type", "Description"], (table.title or "")) }} {% endfor %} Example{% if examples | length > 1 %}s{% endif %}: diff --git a/scripts/templating/matrix_templates/templates/http-api.tmpl b/scripts/templating/matrix_templates/templates/http-api.tmpl index db70da42..1d486cd3 100644 --- a/scripts/templating/matrix_templates/templates/http-api.tmpl +++ b/scripts/templating/matrix_templates/templates/http-api.tmpl @@ -18,7 +18,7 @@ Request format: {{ tables.split_paramtable(endpoint.req_param_by_loc) }} {% if (endpoint.req_body_tables) %} {% for table in endpoint.req_body_tables -%} -{{ tables.paramtable(table.rows, [(table.title or "") ~ " Parameter", "Type", "Description"] ) }} +{{ tables.paramtable(table.rows, caption=(table.title or "")) }} {% endfor -%} {% endif -%} @@ -38,7 +38,7 @@ Response format: {% for table in endpoint.res_tables -%} -{{ tables.paramtable(table.rows, [(table.title or "") ~ " Parameter", "Type", "Description"] ) }} +{{ tables.paramtable(table.rows, caption=(table.title or "")) }} {% endfor %} diff --git a/scripts/templating/matrix_templates/templates/msgtypes.tmpl b/scripts/templating/matrix_templates/templates/msgtypes.tmpl index dfcf2e9d..060a7db0 100644 --- a/scripts/templating/matrix_templates/templates/msgtypes.tmpl +++ b/scripts/templating/matrix_templates/templates/msgtypes.tmpl @@ -5,13 +5,7 @@ {{event.desc | wrap(80)}} {% for table in event.content_fields -%} -{% if table.title -%} -{% set tabletitle = table.title -%} -{% else -%} -{% set tabletitle = "" -%} -{% endif -%} - -{{ tables.paramtable(table.rows, [(table.title or "Content") ~ " Key", "Type", "Description"] ) }} +{{ tables.paramtable(table.rows, [(table.title or "Content") ~ " Key", "Type", "Description"], (table.title or "")) }} {% endfor %} Example: diff --git a/scripts/templating/matrix_templates/templates/tables.tmpl b/scripts/templating/matrix_templates/templates/tables.tmpl index 13ac08c8..fde546a7 100644 --- a/scripts/templating/matrix_templates/templates/tables.tmpl +++ b/scripts/templating/matrix_templates/templates/tables.tmpl @@ -8,8 +8,8 @@ # # 'rows' is the list of parameters. Each row should be a TypeTableRow. #} -{% macro paramtable(rows, titles=["Parameter", "Type", "Description"]) -%} -{{ split_paramtable({None: rows}, titles) }} +{% macro paramtable(rows, titles=["Parameter", "Type", "Description"], caption="") -%} +{{ split_paramtable({None: rows}, titles, caption) }} {% endmacro %} @@ -21,7 +21,7 @@ # written for that location. This is used by the standard 'paramtable' macro. #} {% macro split_paramtable(rows_by_loc, - titles=["Parameter", "Type", "Description"]) -%} + titles=["Parameter", "Type", "Description"], caption="") -%} {% set rowkeys = ['key', 'title', 'desc'] %} {% set titlerow = {'key': titles[0], 'title': titles[1], 'desc': titles[2]} %} @@ -36,11 +36,6 @@ {% set fieldwidths = (([titlerow] + flatrows) | fieldwidths(rowkeys[0:-1], [10, 10])) + [50] -%} -{% set caption = titlerow['key'] | replace (' Key', '') | replace ('Parameter', '') -%} -{% if caption == 'Content' -%} -{% set caption = '' -%} -{% endif -%} - {{".. table:: "}}{{ caption }} {{" :widths: auto"}} {{""}} From f1ae872857125589472521228ee9bff3a025f7f4 Mon Sep 17 00:00:00 2001 From: Ben Parsons Date: Thu, 30 Aug 2018 17:16:45 +0100 Subject: [PATCH 10/26] light zebra striping for tables --- scripts/css/basic.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/css/basic.css b/scripts/css/basic.css index ca21a859..1b2e3526 100644 --- a/scripts/css/basic.css +++ b/scripts/css/basic.css @@ -342,6 +342,10 @@ table.colwidths-auto tr td:nth-child(3) { width: 70%; } +table.colwidths-auto tr:nth-child(even) { + background-color: #f4f4f4; +} + /* -- other body styles ----------------------------------------------------- */ ol.arabic { From a1b1054aa1202c26659ec267ef643704312e5455 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Thu, 30 Aug 2018 15:57:09 -0400 Subject: [PATCH 11/26] fix handling of multi-line state key descriptions --- scripts/templating/matrix_templates/templates/events.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/templating/matrix_templates/templates/events.tmpl b/scripts/templating/matrix_templates/templates/events.tmpl index ded33859..1ad79c6f 100644 --- a/scripts/templating/matrix_templates/templates/events.tmpl +++ b/scripts/templating/matrix_templates/templates/events.tmpl @@ -5,7 +5,7 @@ {% if (event.typeof | length) %} *{{event.typeof}}* - {{event.typeof_info}} + {{event.typeof_info | indent_block(4)}} {% endif -%} From f923d08078654a21d31064d9d515c70465e2c169 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 30 Aug 2018 16:21:31 -0600 Subject: [PATCH 12/26] Add read markers This is the spec for https://github.com/matrix-org/matrix-doc/issues/910 Fixes https://github.com/matrix-org/matrix-doc/issues/910 Some reverse engineering was required to work out the complete details as to how this works. In particular, the 405 for setting account data and the behaviour of m.read. References: * 405 for account data: https://github.com/matrix-org/synapse/blob/d69decd5c78c72abef50b597a689e2bc55a39702/synapse/rest/client/v2_alpha/account_data.py#L85-L90 * m.read behaviour: https://github.com/matrix-org/synapse/blob/d69decd5c78c72abef50b597a689e2bc55a39702/synapse/rest/client/v2_alpha/read_marker.py#L45-L52 --- api/client-server/account-data.yaml | 22 +++++++ api/client-server/read_markers.yaml | 79 ++++++++++++++++++++++++++ event-schemas/examples/m.fully_read | 8 +++ event-schemas/schema/m.fully_read | 29 ++++++++++ specification/modules/read_markers.rst | 70 +++++++++++++++++++++++ specification/targets.yaml | 1 + 6 files changed, 209 insertions(+) create mode 100644 api/client-server/read_markers.yaml create mode 100644 event-schemas/examples/m.fully_read create mode 100644 event-schemas/schema/m.fully_read create mode 100644 specification/modules/read_markers.rst diff --git a/api/client-server/account-data.yaml b/api/client-server/account-data.yaml index 76b2b156..c468f1c0 100644 --- a/api/client-server/account-data.yaml +++ b/api/client-server/account-data.yaml @@ -67,6 +67,17 @@ paths: 200: description: The account_data was successfully added. + 405: + description: + The account data event type cannot be set here. This generally indicates + that another API is available for managing the data contained in the event. + schema: + $ref: "definitions/errors/error.yaml" + examples: + application/json: { + "errcode": "M_UNKNOWN", + "error": "Cannot set m.fully_read through this API. Use /rooms/{roomId}/read_markers" + } tags: - User data "/user/{userId}/rooms/{roomId}/account_data/{type}": @@ -116,5 +127,16 @@ paths: 200: description: The account_data was successfully added. + 405: + description: + The account data event type cannot be set here. This generally indicates + that another API is available for managing the data contained in the event. + schema: + $ref: "definitions/errors/error.yaml" + examples: + application/json: { + "errcode": "M_UNKNOWN", + "error": "Cannot set m.fully_read through this API. Use /rooms/{roomId}/read_markers" + } tags: - User data diff --git a/api/client-server/read_markers.yaml b/api/client-server/read_markers.yaml new file mode 100644 index 00000000..a74592c5 --- /dev/null +++ b/api/client-server/read_markers.yaml @@ -0,0 +1,79 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +swagger: '2.0' +info: + title: "Matrix Client-Server Read Marker API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/%CLIENT_MAJOR_VERSION% +consumes: + - application/json +produces: + - application/json +securityDefinitions: + $ref: definitions/security.yaml +paths: + "/rooms/{roomId}/read_markers": + post: + summary: Set the position of the read marker for a room. + description: |- + Sets the position of the read marker for a given room, and optionally + the read receipt's location. + operationId: setReadMarker + security: + - accessToken: [] + parameters: + - in: path + type: string + name: roomId + description: The room ID to set the read marker in for the user. + required: true + x-example: "!somewhere:domain.com" + - in: body + name: body + description: The read marker and optional read receipt locations. + required: true + schema: + type: object + properties: + "m.fully_read": + type: string + description: |- + The event ID the read marker should be located at. The + event MUST belong to the room. + example: "$somewhere:domain.com" + "m.read": + type: string + description: |- + The event ID to set the read receipt location at. This is + equivalent to calling ``/receipt/m.read/$elsewhere:domain.com`` + and is provided here to save that extra call. + example: "$elsewhere:domain.com" + required: ['m.fully_read'] + responses: + 200: + description: |- + The read marker, and read receipt if provided, have been updated. + schema: + type: object + properties: {} + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/errors/rate_limited.yaml" + tags: + - Read Markers diff --git a/event-schemas/examples/m.fully_read b/event-schemas/examples/m.fully_read new file mode 100644 index 00000000..8278c6fa --- /dev/null +++ b/event-schemas/examples/m.fully_read @@ -0,0 +1,8 @@ +{ + "$ref": "core/event.json", + "type": "m.fully_read", + "room_id": "!somewhere:domain.com", + "content": { + "event_id": "$someplace:domain.com" + } +} diff --git a/event-schemas/schema/m.fully_read b/event-schemas/schema/m.fully_read new file mode 100644 index 00000000..51a1942f --- /dev/null +++ b/event-schemas/schema/m.fully_read @@ -0,0 +1,29 @@ +{ + "type": "object", + "title": "Read Marker Location Event", + "description": "The current location of the user's read marker in a room. This event appears in the user's room account data for the room the marker is applicable for.", + "allOf": [{ + "$ref": "core-event-schema/event.yaml" + }], + "properties": { + "content": { + "type": "object", + "properties": { + "event_id": { + "type": "string", + "description": "The event the user's read marker is located at in the room." + } + }, + "required": ["event_id"] + }, + "type": { + "type": "string", + "enum": ["m.fully_read"] + }, + "room_id": { + "type": "string", + "description": "The room ID the read marker applies to." + } + }, + "required": ["type", "room_id", "content"] +} diff --git a/specification/modules/read_markers.rst b/specification/modules/read_markers.rst new file mode 100644 index 00000000..0a5578d6 --- /dev/null +++ b/specification/modules/read_markers.rst @@ -0,0 +1,70 @@ +.. Copyright 2018 New Vector Ltd +.. +.. Licensed under the Apache License, Version 2.0 (the "License"); +.. you may not use this file except in compliance with the License. +.. You may obtain a copy of the License at +.. +.. http://www.apache.org/licenses/LICENSE-2.0 +.. +.. Unless required by applicable law or agreed to in writing, software +.. distributed under the License is distributed on an "AS IS" BASIS, +.. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +.. See the License for the specific language governing permissions and +.. limitations under the License. + +Read Markers +============ + +.. _module:read-markers: + +A "read marker" is a bookmark in the room's history where the user has last +read a message. Read receipts cover the most recently read message, and have +slightly different semantics where they are to be sent when the user has most +likely seen the message, but not necessarily read it. A read marker tracks +the user's last read message, therefore making the messages between the read +marker and read receipt "potentially read" and messages before the read marker +as "read". Messages after the read receipt should be considered as "unread", +therefore the read marker should always be earlier or equal to the location of +the read receipt. + +Events +------ +The user's read marker is kept as an event in the room's `account data`_. The +event may be read to determine the user's current read marker location in the +room, and just like other account data events the event will be pushed down +the event stream when updated. + +The read marker is kept under an ``m.fully_read`` event. If the event does +not exist on the user's account data, the read marker should be considered +to be the user's read receipt location. + +{{m_fully_read_event}} + +Client behaviour +---------------- +The client cannot update read markers by directly modifying the ``m.fully_read`` +account data event. Instead, the client must make use of the read markers API +to change the values. + +The read markers API can additionally update the user's read receipt (``m.read``) +location in the same operation as setting the read marker location. This is +because read receipts and read markers are commonly updated at the same time, +and therefore the client might wish to save an extra HTTP call. Providing an +``m.read`` location performs the same task as a request to ``/receipts/m.read/$event:domain.com``. + +{{read_markers_cs_http_api}} + +Server behaviour +---------------- +The server MUST prevent clients from setting ``m.fully_read`` directly in +room account data. The server must additionally ensure that it treats the +presence of ``m.read`` in the ``/read_markers`` request the same as how it +would for a request to ``/receipts/m.read/$event:domain.com``. + +Upon updating the ``m.fully_read`` event due to a request to ``/read_markers``, +the server MUST send the updated account data event through to the client via +the event stream (eg: ``/sync``), provided any applicable filters are also +satisfied. + + +.. _`account data`: #client-config diff --git a/specification/targets.yaml b/specification/targets.yaml index 56e9ec34..a2eb5cdd 100644 --- a/specification/targets.yaml +++ b/specification/targets.yaml @@ -45,6 +45,7 @@ groups: # reusable blobs of files when prefixed with 'group:' - modules/voip_events.rst - modules/typing_notifications.rst - modules/receipts.rst + - modules/read_markers.rst - modules/presence.rst - modules/content_repo.rst - modules/send_to_device.rst From 7516af3df20b3cee84f324fd37004ba5b31046b3 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 30 Aug 2018 16:22:56 -0600 Subject: [PATCH 13/26] Changelog --- changelogs/client_server/newsfragments/1635.feature | 1 + changelogs/client_server/newsfragments/1635.new | 1 + 2 files changed, 2 insertions(+) create mode 100644 changelogs/client_server/newsfragments/1635.feature create mode 100644 changelogs/client_server/newsfragments/1635.new diff --git a/changelogs/client_server/newsfragments/1635.feature b/changelogs/client_server/newsfragments/1635.feature new file mode 100644 index 00000000..3a5bb45f --- /dev/null +++ b/changelogs/client_server/newsfragments/1635.feature @@ -0,0 +1 @@ +Add support for read markers. diff --git a/changelogs/client_server/newsfragments/1635.new b/changelogs/client_server/newsfragments/1635.new new file mode 100644 index 00000000..ec57e74b --- /dev/null +++ b/changelogs/client_server/newsfragments/1635.new @@ -0,0 +1 @@ +POST ``/rooms/{roomId}/read_markers`` From e8afab1fe51797e6a5dad4b9d7f4ccfe3159e0f7 Mon Sep 17 00:00:00 2001 From: Ben Parsons Date: Fri, 31 Aug 2018 13:55:27 +0100 Subject: [PATCH 14/26] many visual improvements --- scripts/css/basic.css | 24 ++++++++++++---- .../matrix_templates/templates/http-api.tmpl | 28 +++++++++++++++---- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/scripts/css/basic.css b/scripts/css/basic.css index 1b2e3526..c26bb711 100644 --- a/scripts/css/basic.css +++ b/scripts/css/basic.css @@ -319,10 +319,24 @@ table.citation td { } table.colwidths-auto caption { - font-family: monospace; - font-size: large; - padding: 2px; + font-family: 'Inconsolata', monospace; + font-weight: 800; + font-size: 110%; + padding: 5px; + text-align: left; + margin-bottom: 2px; +} + +ol, li { + margin: 0px 0px 0px 30px !important; +} + +p.httpheaders { + font-weight: 800; + font-size: 120%; + padding: 5px; text-align: left; + margin-bottom: 2px; } table.colwidths-auto { @@ -336,15 +350,13 @@ table.colwidths-auto tr td:nth-child(1) { table.colwidths-auto tr td:nth-child(2) { width: 15%; + font-family: 'Inconsolata', monospace; } table.colwidths-auto tr td:nth-child(3) { width: 70%; } -table.colwidths-auto tr:nth-child(even) { - background-color: #f4f4f4; -} /* -- other body styles ----------------------------------------------------- */ diff --git a/scripts/templating/matrix_templates/templates/http-api.tmpl b/scripts/templating/matrix_templates/templates/http-api.tmpl index 1d486cd3..0b9207d9 100644 --- a/scripts/templating/matrix_templates/templates/http-api.tmpl +++ b/scripts/templating/matrix_templates/templates/http-api.tmpl @@ -13,7 +13,10 @@ {{":Rate-limited: Yes." if endpoint.rate_limited else "" }} {{":Requires auth: Yes." if endpoint.requires_auth else "" }} -Request format: +.. class:: httpheaders + + Request format: + {% if (endpoint.req_param_by_loc | length) %} {{ tables.split_paramtable(endpoint.req_param_by_loc) }} {% if (endpoint.req_body_tables) %} @@ -28,13 +31,19 @@ Request format: {% endif %} {% if endpoint.res_headers is not none -%} -Response headers: + +.. class:: httpheaders + + Response headers: {{ tables.paramtable(endpoint.res_headers.rows) }} {% endif -%} {% if endpoint.res_tables|length > 0 -%} -Response format: + +.. class:: httpheaders + + Response format: {% for table in endpoint.res_tables -%} @@ -44,14 +53,19 @@ Response format: {% endfor %} {% endif -%} -Example request: +.. class:: httpheaders + + Example request: .. code:: http {{endpoint.example.req | indent_block(2)}} {% if endpoint.responses|length > 0 -%} -Response{{"s" if endpoint.responses|length > 1 else "" }}: + +.. class:: httpheaders + + Response{{"s" if endpoint.responses|length > 1 else "" }}: {% endif -%} @@ -63,7 +77,9 @@ Response{{"s" if endpoint.responses|length > 1 else "" }}: {% if res["example"] -%} -Example +.. class:: httpheaders + + Example .. code:: json From 778fe2a47aa3a659bca4f985256cf9c2c98a107f Mon Sep 17 00:00:00 2001 From: Ben Parsons Date: Fri, 31 Aug 2018 14:29:46 +0100 Subject: [PATCH 15/26] css caption size tweak --- scripts/css/basic.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/css/basic.css b/scripts/css/basic.css index c26bb711..1112cdfc 100644 --- a/scripts/css/basic.css +++ b/scripts/css/basic.css @@ -321,7 +321,7 @@ table.citation td { table.colwidths-auto caption { font-family: 'Inconsolata', monospace; font-weight: 800; - font-size: 110%; + font-size: 120%; padding: 5px; text-align: left; margin-bottom: 2px; From c77b505441c2e088a00cf54efc16758b05601418 Mon Sep 17 00:00:00 2001 From: Ben Parsons Date: Fri, 31 Aug 2018 14:37:47 +0100 Subject: [PATCH 16/26] capitali[zs]e path parameters --- scripts/css/nature.css | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/css/nature.css b/scripts/css/nature.css index 0fdcc55a..5fd4fae5 100644 --- a/scripts/css/nature.css +++ b/scripts/css/nature.css @@ -273,6 +273,7 @@ table { td[colspan]:not([colspan="1"]) { background: #eeeeee; + text-transform: capitalize; } thead { From e3daf10bb965beed3e33a86b616532aa1a303870 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Fri, 31 Aug 2018 12:11:27 -0400 Subject: [PATCH 17/26] refactor encrypted file schema as "Extension to m.message" --- .../examples/m.room.message.encrypted_file | 55 -------- .../msgtype_infos/image_info.yaml | 6 + event-schemas/schema/m.room.message#m.audio | 9 +- event-schemas/schema/m.room.message#m.file | 15 ++- event-schemas/schema/m.room.message#m.image | 9 +- .../schema/m.room.message#m.location | 6 + event-schemas/schema/m.room.message#m.video | 15 ++- .../schema/m.room.message.encrypted_file | 100 --------------- .../modules/end_to_end_encryption.rst | 118 ++++++++++++++++-- 9 files changed, 162 insertions(+), 171 deletions(-) delete mode 100644 event-schemas/examples/m.room.message.encrypted_file delete mode 100644 event-schemas/schema/m.room.message.encrypted_file diff --git a/event-schemas/examples/m.room.message.encrypted_file b/event-schemas/examples/m.room.message.encrypted_file deleted file mode 100644 index 1b157922..00000000 --- a/event-schemas/examples/m.room.message.encrypted_file +++ /dev/null @@ -1,55 +0,0 @@ -{ - "age": 146, - "content": { - "body": "something-important.doc", - "filename": "something-important.doc", - "file": { - "url": "mxc://localhost/FHyPlCeYUSFFxlgbQYZmoEoe", - "mimetype": "application/msword", - "v": "v2", - "key": { - "alg": "A256CTR", - "ext": true, - "k": "aWF6-32KGYaC3A_FEUCk1Bt0JA37zP0wrStgmdCaW-0", - "key_ops": ["encrypt","decrypt"], - "kty": "oct" - }, - "iv": "w+sE15fzSc0AAAAAAAAAAA", - "hashes": { - "sha256": "fdSLu/YkRx3Wyh3KQabP3rd6+SFiKg5lsJZQHtkSAYA" - } - }, - "info": { - "mimetype": "application/msword", - "size": 46144, - "thumbnail_file": { - "hashes": { - "sha256": "/NogKqW5bz/m8xHgFiH5haFGjCNVmUIPLzfvOhHdrxY" - }, - "iv": "U+k7PfwLr6UAAAAAAAAAAA", - "key": { - "alg": "A256CTR", - "ext": true, - "k": "RMyd6zhlbifsACM1DXkCbioZ2u0SywGljTH8JmGcylg", - "key_ops": ["encrypt", "decrypt"], - "kty": "oct" - }, - "mimetype": "image/jpeg", - "url": "mxc://localhost/pmVJxyxGlmxHposwVSlOaEOv", - "v": "v2" - }, - "thumbnail_info": { - "h": 768, - "mimetype": "image/jpeg", - "size": 211009, - "w": 432 - } - }, - "msgtype": "m.file" - }, - "event_id": "$143273582443PhrSn:localhost", - "origin_server_ts": 1432735824653, - "room_id": "!jEsUZKDJdhlrceRyVU:localhost", - "type": "m.room.message", - "sender": "@example:localhost" -} diff --git a/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml b/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml index 4d2a9964..210c3837 100644 --- a/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml +++ b/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml @@ -20,6 +20,12 @@ properties: thumbnail_url: description: The URL to a thumbnail of the image. type: string + thumbnail_file: + description: |- + Information on the encrypted thumbnail file, as specified in + |encrypted_files|_. + title: EncryptedFile + type: object thumbnail_info: allOf: - $ref: thumbnail_info.yaml diff --git a/event-schemas/schema/m.room.message#m.audio b/event-schemas/schema/m.room.message#m.audio index f15c71a3..c258b85f 100644 --- a/event-schemas/schema/m.room.message#m.audio +++ b/event-schemas/schema/m.room.message#m.audio @@ -27,12 +27,17 @@ properties: - m.audio type: string url: - description: The URL to the audio clip. + description: Required if the file is not encrypted. The URL to the audio clip. type: string + file: + description: |- + Required if the file is encrypted. Information on the encrypted + file, as specified in |encrypted_files|_. + title: EncryptedFile + type: object required: - msgtype - body - - url type: object type: enum: diff --git a/event-schemas/schema/m.room.message#m.file b/event-schemas/schema/m.room.message#m.file index 76e59e09..81f7ace6 100644 --- a/event-schemas/schema/m.room.message#m.file +++ b/event-schemas/schema/m.room.message#m.file @@ -23,6 +23,12 @@ properties: thumbnail_url: description: The URL to the thumbnail of the file. type: string + thumbnail_file: + description: |- + Information on the encrypted thumbnail file, as specified in + |encrypted_files|_. + title: EncryptedFile + type: object thumbnail_info: allOf: - $ref: core-event-schema/msgtype_infos/thumbnail_info.yaml @@ -34,12 +40,17 @@ properties: - m.file type: string url: - description: The URL to the file. + description: Required if the file is unencrypted. The URL to the file. type: string + file: + description: |- + Required if the file is encrypted. Information on the encrypted + file, as specified in |encrypted_files|_. + title: EncryptedFile + type: object required: - msgtype - body - - url - filename type: object type: diff --git a/event-schemas/schema/m.room.message#m.image b/event-schemas/schema/m.room.message#m.image index 1237b8f8..349f78f4 100644 --- a/event-schemas/schema/m.room.message#m.image +++ b/event-schemas/schema/m.room.message#m.image @@ -17,12 +17,17 @@ properties: - m.image type: string url: - description: The URL to the image. + description: Required if the file is unencrypted. The URL to the image. type: string + file: + description: |- + Required if the file is encrypted. Information on the encrypted + file, as specified in |encrypted_files|_. + title: EncryptedFile + type: object required: - msgtype - body - - url type: object type: enum: diff --git a/event-schemas/schema/m.room.message#m.location b/event-schemas/schema/m.room.message#m.location index e8d55769..2d01db63 100644 --- a/event-schemas/schema/m.room.message#m.location +++ b/event-schemas/schema/m.room.message#m.location @@ -21,6 +21,12 @@ properties: thumbnail_url: description: The URL to a thumbnail of the location being represented. type: string + thumbnail_file: + description: |- + Information on the encrypted thumbnail file, as specified in + |encrypted_files|_. + title: EncryptedFile + type: object thumbnail_info: allOf: - $ref: core-event-schema/msgtype_infos/thumbnail_info.yaml diff --git a/event-schemas/schema/m.room.message#m.video b/event-schemas/schema/m.room.message#m.video index a0240b54..553678c8 100644 --- a/event-schemas/schema/m.room.message#m.video +++ b/event-schemas/schema/m.room.message#m.video @@ -29,6 +29,12 @@ properties: thumbnail_url: description: The URL to an image thumbnail of the video clip. type: string + thumbnail_file: + description: |- + Information on the encrypted thumbnail file, as specified in + |encrypted_files|_. + title: EncryptedFile + type: object thumbnail_info: allOf: - $ref: core-event-schema/msgtype_infos/thumbnail_info.yaml @@ -40,12 +46,17 @@ properties: - m.video type: string url: - description: The URL to the video clip. + description: Required if the file is unencrypted. The URL to the video clip. type: string + file: + description: |- + Required if the file is encrypted. Information on the encrypted + file, as specified in |encrypted_files|_. + title: EncryptedFile + type: object required: - msgtype - body - - url type: object type: enum: diff --git a/event-schemas/schema/m.room.message.encrypted_file b/event-schemas/schema/m.room.message.encrypted_file deleted file mode 100644 index 4f9229b7..00000000 --- a/event-schemas/schema/m.room.message.encrypted_file +++ /dev/null @@ -1,100 +0,0 @@ ---- -allOf: - - $ref: core-event-schema/room_event.yaml -description: |- - This message represents an encrypted generic file, corresponding to a - plaintext ``m.file`` message. ``m.image``, ``m.video`` and ``m.audio`` can be - sent encrypted using the same structure. -properties: - content: - properties: - body: - description: |- - A human-readable description of the file. This is recommended to be - the filename of the original upload. - type: string - filename: - description: The original filename of the uploaded file. - type: string - info: - description: Information about the file referred to in ``file``. - properties: - mimetype: - description: The mimetype of the file e.g. ``application/msword``. - type: string - size: - description: The size of the file in bytes. - type: integer - thumbnail_file: - description: The URL to the thumbnail of the file. - title: EncryptedFile - type: object - thumbnail_info: - allOf: - - $ref: core-event-schema/msgtype_infos/thumbnail_info.yaml - description: Metadata about the image referred to in ``thumbnail_url``. - title: FileInfo - type: object - msgtype: - enum: - - m.file - type: string - file: - description: Information needed to decrypt the file. - properties: - url: - description: The URL to the file. - type: string - key: - description: A `JSON web key`_ object. - type: object - title: JWK - properties: - kty: - description: Key type. Must be ``oct``. - type: string - key_ops: - description: |- - Key operations. Must at least contain ``encrypt`` and ``decrypt``. - type: array - items: - type: string - alg: - description: Algorithm. Must be ``A256CTR``. - type: string - k: - description: The key, encoded as urlsafe unpadded base64. - type: string - ext: - description: Extractable. Must be ``true``. This is a `W3C extension`_. - type: boolean - iv: - description: |- - The Initialisation Vector used by AES-CTR, encoded as unpadded - base64. - type: string - hashes: - description: |- - A map from an algorithm name to a hash of the ciphertext, encoded - as unpadded base64. Clients should support the SHA-256 hash. - type: object - additionalProperties: - type: string - v: - description: Version of the encrypted attachments protocol. - type: string - enum: ["v2"] - title: EncryptedFile - type: object - required: - - msgtype - - body - - file - - filename - type: object - type: - enum: - - m.room.message - type: string -title: EncryptedFileMessage -type: object diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index e5bc0cb0..950b3041 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -250,14 +250,116 @@ the decrypted file. A hash of the ciphertext must also be included, in order to prevent the homeserver from changing the file content. -A client should send the data as a ``m.room.message`` event, using either -``m.file`` as the msgtype, or the appropriate msgtype for the file type. The -structure is similar to an unencrypted file message, except for two differing -keys: ``url`` and ``thumbnail_url`` are replaced respectively by ``file`` and -``thumbnail_file``, containing an ``EncryptedFile`` object as specified below. -The key is sent using the `JSON Web Key`_ format, with a `W3C extension`_. - -{{m_room_message_encrypted_file_event}} +A client should send the data as an encrypted ``m.room.message`` event, using +either ``m.file`` as the msgtype, or the appropriate msgtype for the file +type. The key is sent using the `JSON Web Key`_ format, with a `W3C +extension`_. + +.. anchor for link from m.message api spec +.. |encrypted_files| replace:: End-to-end encryption +.. _encrypted_files: + +Extensions to ``m.message`` msgtypes +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + +This module adds ``file`` and ``thumbnail_file`` properties to ``m.message`` +msgtypes that reference files, such as ``m.file`` and ``m.image``, replacing +the ``url`` and ``thumbnail_url`` properties. + +.. todo: generate this from a swagger definition? + +``EncryptedFile`` + +========= ================ ===================================================== +Parameter Type Description +========= ================ ===================================================== +url string The URL to the file. +key JWK A `JSON Web Key`_ object. +iv string The Initialisation Vector used by AES-CTR, encoded as + unpadded base64. +hashes {string: string} A map from an algorithm name to a hash of the + ciphertext, encoded as unpadded base64. Clients + should support the SHA-256 hash, which uses the key + ``sha256``. +v string Version of the encrypted attachments protocol. Must + be ``v2``. +========= ================ ===================================================== + +``JWK`` + +========= ========= ============================================================ +Parameter Type Description +========= ========= ============================================================ +key string Key type. Must be ``oct``. +key_opts [string] Key operations. Must at least contain ``encrypt`` and + ``decrypt``. +alg string Algorithm. Must be ``A256CTR``. +k string The key, encoded as urlsafe unpadded base64. +ext boolean Extractable. Must be ``true``. This is a `W3C extension`_. +========= ========= ============================================================ + +Example: + +.. code :: json + + { + "content": { + "body": "something-important.jpg", + "file": { + "url": "mxc://domain.com/FHyPlCeYUSFFxlgbQYZmoEoe", + "mimetype": "image/jpeg", + "v": "v2", + "key": { + "alg": "A256CTR", + "ext": true, + "k": "aWF6-32KGYaC3A_FEUCk1Bt0JA37zP0wrStgmdCaW-0", + "key_ops": ["encrypt","decrypt"], + "kty": "oct" + }, + "iv": "w+sE15fzSc0AAAAAAAAAAA", + "hashes": { + "sha256": "fdSLu/YkRx3Wyh3KQabP3rd6+SFiKg5lsJZQHtkSAYA" + } + }, + "info": { + "mimetype": "image/jpeg", + "h": 1536, + "size": 422018, + "thumbnail_file": { + "hashes": { + "sha256": "/NogKqW5bz/m8xHgFiH5haFGjCNVmUIPLzfvOhHdrxY" + }, + "iv": "U+k7PfwLr6UAAAAAAAAAAA", + "key": { + "alg": "A256CTR", + "ext": true, + "k": "RMyd6zhlbifsACM1DXkCbioZ2u0SywGljTH8JmGcylg", + "key_ops": ["encrypt", "decrypt"], + "kty": "oct" + }, + "mimetype": "image/jpeg", + "url": "mxc://domain.com/pmVJxyxGlmxHposwVSlOaEOv", + "v": "v2" + }, + "thumbnail_info": { + "h": 768, + "mimetype": "image/jpeg", + "size": 211009, + "w": 432 + }, + "w": 864 + }, + "msgtype": "m.image" + }, + "event_id": "$143273582443PhrSn:domain.com", + "origin_server_ts": 1432735824653, + "room_id": "!jEsUZKDJdhlrceRyVU:domain.com", + "sender": "@example:domain.com", + "type": "m.room.message", + "unsigned": { + "age": 1234 + } + } Claiming one-time keys ~~~~~~~~~~~~~~~~~~~~~~ From 567843e043b931963772cf0598a3990c25d573ea Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 31 Aug 2018 10:20:26 -0600 Subject: [PATCH 18/26] Add additional clarity to how rich replies are structured and used --- specification/modules/instant_messaging.rst | 66 ++++++++++++++++----- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/specification/modules/instant_messaging.rst b/specification/modules/instant_messaging.rst index 31e0b50e..be030050 100644 --- a/specification/modules/instant_messaging.rst +++ b/specification/modules/instant_messaging.rst @@ -62,9 +62,9 @@ support an additional ``format`` parameter of ``org.matrix.custom.html``. When this field is present, a ``formatted_body`` with the HTML must be provided. The plain text version of the HTML should be provided in the ``body``. -Clients should limit the HTML they render to avoid Cross-Site Scripting, HTML +Clients should limit the HTML they render to avoid Cross-Site Scripting, HTML injection, and similar attacks. The strongly suggested set of HTML tags to permit, -denying the use and rendering of anything else, is: ``font``, ``del``, ``h1``, +denying the use and rendering of anything else, is: ``font``, ``del``, ``h1``, ``h2``, ``h3``, ``h4``, ``h5``, ``h6``, ``blockquote``, ``p``, ``a``, ``ul``, ``ol``, ``sup``, ``sub``, ``li``, ``b``, ``i``, ``u``, ``strong``, ``em``, ``strike``, ``code``, ``hr``, ``br``, ``div``, ``table``, ``thead``, ``tbody``, @@ -73,7 +73,7 @@ denying the use and rendering of anything else, is: ``font``, ``del``, ``h1``, Not all attributes on those tags should be permitted as they may be avenues for other disruption attempts, such as adding ``onclick`` handlers or excessively large text. Clients should only permit the attributes listed for the tags below. -Where ``data-mx-bg-color`` and ``data-mx-color`` are listed, clients should +Where ``data-mx-bg-color`` and ``data-mx-color`` are listed, clients should translate the value (a 6-character hex color code) to the appropriate CSS/attributes for the tag. @@ -366,7 +366,20 @@ thread-like conversation. Relationships are defined under an ``m.relates_to`` key in the event's ``content``. If the event is of the type ``m.room.encrypted``, the ``m.relates_to`` key MUST NOT be covered by the encryption and instead be put alongside the encryption information -held in the ``content``. +held in the ``content``, like in the following example:: + + { + ... + "content": { + ... + "m.relates_to": { + "m.in_reply_to": { + ... + } + } + } + } + Rich replies ++++++++++++ @@ -376,14 +389,34 @@ clients may wish to better embed the referenced message for the user to have a better context for the conversation being had. This sort of embedding another message in a message is known as a "rich reply", or occasionally just a "reply". -Rich replies may reference another event which also has a rich reply, infinitely. A rich reply is formed through use of an ``m.relates_to`` relation for ``m.in_reply_to`` where a single key, ``event_id``, is used to reference the event being replied to. -The referenced event ID MUST belong to the same room where the reply is being sent. -Rich replies can only be constructed in the form of ``m.room.message`` events with -a ``msgtype`` of ``m.text`` or ``m.notice``. Due to the fallback requirements, rich +The referenced event ID SHOULD belong to the same room where the reply is being sent. +Clients should be cautious of the event ID belonging to another room, or being invalid +entirely. Rich replies can only be constructed in the form of ``m.room.message`` events +with a ``msgtype`` of ``m.text`` or ``m.notice``. Due to the fallback requirements, rich replies cannot be constructed for types of ``m.emote``, ``m.file``, etc. Rich replies -may reference any other ``m.room.message`` event, however. +may reference any other ``m.room.message`` event, however. Rich replies may reference +another event which also has a rich reply, infinitely. + +An ``m.in_reply_to`` relationship looks like the following:: + + { + ... + "type": "m.room.message", + "content": { + "msgtype": "m.text", + "body": "", + "format": "org.matrix.custom.html", + "formatted_body": "", + "m.relates_to": { + "m.in_reply_to": { + "event_id": "$another:event.com" + } + } + } + } + Fallbacks and event representation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -393,9 +426,9 @@ to use instead. Clients that do not support rich replies should render the event as if rich replies were not special. Clients that do support rich replies MUST provide the fallback format on replies, -and MUST strip the fallback before rendering the reply. Rich replies MUST supply +and MUST strip the fallback before rendering the reply. Rich replies MUST have a ``format`` of ``org.matrix.custom.html`` and therefore a ``formatted_body`` -alongside the ``body`` and appropriate ``msgtype``. The specific fall back text +alongside the ``body`` and appropriate ``msgtype``. The specific fallback text is different for each ``msgtype``, however the general format for the ``body`` is: .. code-block:: text @@ -405,7 +438,7 @@ is different for each ``msgtype``, however the general format for the ``body`` i This is where the reply goes -The ``formatted_body`` ends up using the following template: +The ``formatted_body`` should use the following template: .. code-block:: html @@ -491,9 +524,10 @@ Fallback for ``m.image``, ``m.video``, ``m.audio``, and ``m.file`` The related event's ``body`` would be a file name, which may not be very descriptive. The related event should additionally not have a ``format`` or ``formatted_body`` -in the ``content`` - if the event does, it should be ignored. Because the filename -alone may not be descriptive, the related event's ``body`` should be considered -to be ``"sent a file."`` such that the output looks similar to the following:: +in the ``content`` - if the event does have a ``format`` and/or ``formatted_body``, +those fields should be ignored. Because the filename alone may not be descriptive, +the related event's ``body`` should be considered to be ``"sent a file."`` such that +the output looks similar to the following:: > <@alice:example.org> sent a file. @@ -533,4 +567,4 @@ Clients should sanitise **all displayed keys** for unsafe HTML to prevent Cross- Scripting (XSS) attacks. This includes room names and topics. .. _`E2E module`: `module:e2e`_ -.. _`Matrix Content (MXC) URI`: `module:content`_ \ No newline at end of file +.. _`Matrix Content (MXC) URI`: `module:content`_ From f1f32d3a15c325ee8aa9d2c6bafd96c38069bb53 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Fri, 31 Aug 2018 12:59:57 -0400 Subject: [PATCH 19/26] add more clarifications --- .../msgtype_infos/image_info.yaml | 6 ++-- event-schemas/schema/m.room.message#m.file | 6 ++-- .../schema/m.room.message#m.location | 6 ++-- event-schemas/schema/m.room.message#m.video | 6 ++-- .../modules/end_to_end_encryption.rst | 36 ++++++++++--------- 5 files changed, 35 insertions(+), 25 deletions(-) diff --git a/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml b/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml index 210c3837..8ff27b1e 100644 --- a/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml +++ b/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml @@ -18,12 +18,14 @@ properties: description: Size of the image in bytes. type: integer thumbnail_url: - description: The URL to a thumbnail of the image. + description: |- + The URL to a thumbnail of the image. Only present if the + thumbnail is unencrypted. type: string thumbnail_file: description: |- Information on the encrypted thumbnail file, as specified in - |encrypted_files|_. + |encrypted_files|_. Only present if the thumbnail is encrypted. title: EncryptedFile type: object thumbnail_info: diff --git a/event-schemas/schema/m.room.message#m.file b/event-schemas/schema/m.room.message#m.file index 81f7ace6..2fb4fe50 100644 --- a/event-schemas/schema/m.room.message#m.file +++ b/event-schemas/schema/m.room.message#m.file @@ -21,12 +21,14 @@ properties: description: The size of the file in bytes. type: integer thumbnail_url: - description: The URL to the thumbnail of the file. + description: |- + The URL to the thumbnail of the file. Only present if the + thumbnail is unencrypted. type: string thumbnail_file: description: |- Information on the encrypted thumbnail file, as specified in - |encrypted_files|_. + |encrypted_files|_. Only present if the thumbnail is encrypted. title: EncryptedFile type: object thumbnail_info: diff --git a/event-schemas/schema/m.room.message#m.location b/event-schemas/schema/m.room.message#m.location index 2d01db63..ffc4edce 100644 --- a/event-schemas/schema/m.room.message#m.location +++ b/event-schemas/schema/m.room.message#m.location @@ -19,12 +19,14 @@ properties: type: object properties: thumbnail_url: - description: The URL to a thumbnail of the location being represented. + description: |- + The URL to the thumbnail of the file. Only present if the + thumbnail is unencrypted. type: string thumbnail_file: description: |- Information on the encrypted thumbnail file, as specified in - |encrypted_files|_. + |encrypted_files|_. Only present if the thumbnail is encrypted. title: EncryptedFile type: object thumbnail_info: diff --git a/event-schemas/schema/m.room.message#m.video b/event-schemas/schema/m.room.message#m.video index 553678c8..8a66fdeb 100644 --- a/event-schemas/schema/m.room.message#m.video +++ b/event-schemas/schema/m.room.message#m.video @@ -27,12 +27,14 @@ properties: description: The size of the video in bytes. type: integer thumbnail_url: - description: The URL to an image thumbnail of the video clip. + description: |- + The URL to an image thumbnail of the video clip. Only present if the + thumbnail is unencrypted. type: string thumbnail_file: description: |- Information on the encrypted thumbnail file, as specified in - |encrypted_files|_. + |encrypted_files|_. Only present if the thumbnail is encrypted. title: EncryptedFile type: object thumbnail_info: diff --git a/specification/modules/end_to_end_encryption.rst b/specification/modules/end_to_end_encryption.rst index 950b3041..c5e40a88 100644 --- a/specification/modules/end_to_end_encryption.rst +++ b/specification/modules/end_to_end_encryption.rst @@ -262,9 +262,10 @@ extension`_. Extensions to ``m.message`` msgtypes <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< -This module adds ``file`` and ``thumbnail_file`` properties to ``m.message`` -msgtypes that reference files, such as ``m.file`` and ``m.image``, replacing -the ``url`` and ``thumbnail_url`` properties. +This module adds ``file`` and ``thumbnail_file`` properties, of type +``EncryptedFile``, to ``m.message`` msgtypes that reference files, such as +`m.file`_ and `m.image`_, replacing the ``url`` and ``thumbnail_url`` +properties. .. todo: generate this from a swagger definition? @@ -273,16 +274,16 @@ the ``url`` and ``thumbnail_url`` properties. ========= ================ ===================================================== Parameter Type Description ========= ================ ===================================================== -url string The URL to the file. -key JWK A `JSON Web Key`_ object. -iv string The Initialisation Vector used by AES-CTR, encoded as - unpadded base64. -hashes {string: string} A map from an algorithm name to a hash of the - ciphertext, encoded as unpadded base64. Clients +url string **Required.** The URL to the file. +key JWK **Required.** A `JSON Web Key`_ object. +iv string **Required.** The Initialisation Vector used by + AES-CTR, encoded as unpadded base64. +hashes {string: string} **Required.** A map from an algorithm name to a hash + of the ciphertext, encoded as unpadded base64. Clients should support the SHA-256 hash, which uses the key ``sha256``. -v string Version of the encrypted attachments protocol. Must - be ``v2``. +v string **Required.** Version of the encrypted attachments + protocol. Must be ``v2``. ========= ================ ===================================================== ``JWK`` @@ -290,12 +291,13 @@ v string Version of the encrypted attachments protocol. Must ========= ========= ============================================================ Parameter Type Description ========= ========= ============================================================ -key string Key type. Must be ``oct``. -key_opts [string] Key operations. Must at least contain ``encrypt`` and - ``decrypt``. -alg string Algorithm. Must be ``A256CTR``. -k string The key, encoded as urlsafe unpadded base64. -ext boolean Extractable. Must be ``true``. This is a `W3C extension`_. +key string **Required.** Key type. Must be ``oct``. +key_opts [string] **Required.** Key operations. Must at least contain + ``encrypt`` and ``decrypt``. +alg string **Required.** Algorithm. Must be ``A256CTR``. +k string **Required.** The key, encoded as urlsafe unpadded base64. +ext boolean **Required.** Extractable. Must be ``true``. This is a + `W3C extension`_. ========= ========= ============================================================ Example: From 2e8151999e4e577ce2f539f876790583b373f4b0 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 31 Aug 2018 11:13:19 -0600 Subject: [PATCH 20/26] Clarify that read markers are fully read markers --- specification/modules/read_markers.rst | 33 ++++++++++++-------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/specification/modules/read_markers.rst b/specification/modules/read_markers.rst index 0a5578d6..b2f77bc0 100644 --- a/specification/modules/read_markers.rst +++ b/specification/modules/read_markers.rst @@ -12,42 +12,39 @@ .. See the License for the specific language governing permissions and .. limitations under the License. -Read Markers -============ +Fully read markers +================== .. _module:read-markers: -A "read marker" is a bookmark in the room's history where the user has last -read a message. Read receipts cover the most recently read message, and have -slightly different semantics where they are to be sent when the user has most -likely seen the message, but not necessarily read it. A read marker tracks -the user's last read message, therefore making the messages between the read -marker and read receipt "potentially read" and messages before the read marker -as "read". Messages after the read receipt should be considered as "unread", -therefore the read marker should always be earlier or equal to the location of -the read receipt. +The history for a given room may be split into three sections: messages the +user has read (or indicated they aren't interested in them), messages the user +might have read some but not others, and messages the user hasn't seen yet. +The "fully read marker" (also known as a "read marker") marks the last event +of the first section, whereas the user's read receipt marks the last event of +the second section. Events ------ -The user's read marker is kept as an event in the room's `account data`_. The -event may be read to determine the user's current read marker location in the -room, and just like other account data events the event will be pushed down +The user's fully read marker is kept as an event in the room's `account data`_. +The event may be read to determine the user's current fully read marker location +in the room, and just like other account data events the event will be pushed down the event stream when updated. -The read marker is kept under an ``m.fully_read`` event. If the event does -not exist on the user's account data, the read marker should be considered +The fully read marker is kept under an ``m.fully_read`` event. If the event does +not exist on the user's account data, the fully read marker should be considered to be the user's read receipt location. {{m_fully_read_event}} Client behaviour ---------------- -The client cannot update read markers by directly modifying the ``m.fully_read`` +The client cannot update fully read markers by directly modifying the ``m.fully_read`` account data event. Instead, the client must make use of the read markers API to change the values. The read markers API can additionally update the user's read receipt (``m.read``) -location in the same operation as setting the read marker location. This is +location in the same operation as setting the fully read marker location. This is because read receipts and read markers are commonly updated at the same time, and therefore the client might wish to save an extra HTTP call. Providing an ``m.read`` location performs the same task as a request to ``/receipts/m.read/$event:domain.com``. From f6d9e53f5ce1f6e8382939f5ff538a6342aed7db Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 31 Aug 2018 11:13:32 -0600 Subject: [PATCH 21/26] Clarify that homeserver must reject clients from setting m.fully_read --- api/client-server/account-data.yaml | 22 ---------------------- specification/modules/account_data.rst | 7 +++++++ 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/api/client-server/account-data.yaml b/api/client-server/account-data.yaml index c468f1c0..76b2b156 100644 --- a/api/client-server/account-data.yaml +++ b/api/client-server/account-data.yaml @@ -67,17 +67,6 @@ paths: 200: description: The account_data was successfully added. - 405: - description: - The account data event type cannot be set here. This generally indicates - that another API is available for managing the data contained in the event. - schema: - $ref: "definitions/errors/error.yaml" - examples: - application/json: { - "errcode": "M_UNKNOWN", - "error": "Cannot set m.fully_read through this API. Use /rooms/{roomId}/read_markers" - } tags: - User data "/user/{userId}/rooms/{roomId}/account_data/{type}": @@ -127,16 +116,5 @@ paths: 200: description: The account_data was successfully added. - 405: - description: - The account data event type cannot be set here. This generally indicates - that another API is available for managing the data contained in the event. - schema: - $ref: "definitions/errors/error.yaml" - examples: - application/json: { - "errcode": "M_UNKNOWN", - "error": "Cannot set m.fully_read through this API. Use /rooms/{roomId}/read_markers" - } tags: - User data diff --git a/specification/modules/account_data.rst b/specification/modules/account_data.rst index d0ed201a..f0bf285f 100644 --- a/specification/modules/account_data.rst +++ b/specification/modules/account_data.rst @@ -39,3 +39,10 @@ Client Behaviour ---------------- {{account_data_cs_http_api}} + + +Server Behaviour +---------------- + +Servers MUST reject clients from setting account data for event types that +the server manages. Currently, this only includes `m.fully_read`_. From 4b9fb996446281182cc2355244eab9ef594c8de5 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 31 Aug 2018 11:18:54 -0600 Subject: [PATCH 22/26] Take out unhelpful example --- specification/modules/instant_messaging.rst | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/specification/modules/instant_messaging.rst b/specification/modules/instant_messaging.rst index be030050..406911ea 100644 --- a/specification/modules/instant_messaging.rst +++ b/specification/modules/instant_messaging.rst @@ -366,19 +366,7 @@ thread-like conversation. Relationships are defined under an ``m.relates_to`` key in the event's ``content``. If the event is of the type ``m.room.encrypted``, the ``m.relates_to`` key MUST NOT be covered by the encryption and instead be put alongside the encryption information -held in the ``content``, like in the following example:: - - { - ... - "content": { - ... - "m.relates_to": { - "m.in_reply_to": { - ... - } - } - } - } +held in the ``content``. Rich replies From f4c5c209f346821c769a17b612cdda6d416db681 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 31 Aug 2018 12:36:08 -0600 Subject: [PATCH 23/26] Generalize language for pagination Previously the section was very strict in what pagination was, however this isn't the reality for the matrix specification. Several endpoints have their own pagination naming conventions and do not follow those mandated by this section. This commit generalizes the language to cover those endpoints while also describing how pagination works. In particular, it describes the rough API shape to expect and how to deal with the responses. This commit also removes the `M_BAD_PAGINATION` error as it is not used in the real world. Homeservers are instead encouraged to use the standard `M_INVALID_PARAM` or similar error code. Fixes https://github.com/matrix-org/matrix-doc/issues/610 Fixes https://github.com/matrix-org/matrix-doc/issues/1523 --- specification/client_server_api.rst | 80 ++++++++++------------------- 1 file changed, 28 insertions(+), 52 deletions(-) diff --git a/specification/client_server_api.rst b/specification/client_server_api.rst index 2f17e4c3..a329aa0c 100644 --- a/specification/client_server_api.rst +++ b/specification/client_server_api.rst @@ -138,9 +138,6 @@ Some requests have unique error codes: :``M_INVALID_ROOM_STATE``: Sent when the intial state given to the ``createRoom`` API is invalid. -:``M_BAD_PAGINATION``: - Encountered when specifying bad pagination query parameters. - :``M_THREEPID_IN_USE``: Sent when a threepid given to an API cannot be used because the same threepid is already in use. @@ -1018,39 +1015,21 @@ Pagination is the process of dividing a dataset into multiple discrete pages. Matrix makes use of pagination to allow clients to view extremely large datasets. These datasets are not limited to events in a room (for example clients may want to paginate a list of rooms in addition to events within those rooms). Regardless -of *what* is being paginated, there is a common underlying API which is used to -to give clients a consistent way of selecting subsets of a potentially changing -dataset. Requests pass in ``from``, ``to``, ``dir`` and ``limit`` parameters -which describe where to read from the stream. ``from`` and ``to`` are opaque -textual 'stream tokens' which describe the current position in the dataset. -The ``dir`` parameter is an enum representing the direction of events to return: -either ``f`` orwards or ``b`` ackwards. The response returns new ``start`` and -``end`` stream token values which can then be passed to subsequent requests to -continue pagination. Not all endpoints will make use of all the parameters -outlined here: see the specific endpoint in question for more information. - -Pagination Request Query Parameters -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Query parameters: - from: - $streamtoken - The opaque token to start streaming from. - to: - $streamtoken - The opaque token to end streaming at. Typically, - clients will not know the item of data to end at, so this will usually be - omitted. - limit: - integer - An integer representing the maximum number of items to - return. - dir: - f|b - The direction to return events in. Typically this is ``b`` to paginate - backwards in time. - -'START' and 'END' are placeholder values used in these examples to describe the -start and end of the dataset respectively. - -Unless specified, the default pagination parameters are ``from=START``, -``to=END``, without a limit set. +of what is being paginated, there is a common approach which is used to give +clients an easy way of selecting subsets of a potentially changing dataset. Each +endpoint that uses pagination may use different parameters, however the theme +amoung them is that they take a ``from`` and ``to`` token, and occasionally +a ``limit`` and ``dir`` to describe the direction to look in. Together, these +parameters describe the position in a data set, where ``from`` and ``to`` are +known as "stream tokens" matching the regular expression ``[a-zA-Z0-9.=_-]+``. +If supported, the ``dir`` defines the direction of events to return: either +forwards (``f``) or backwards (``b``). The response contains a ``start`` or +``prev_batch`` token which references the result set immediately prior to the +returned set. The response might additionally have an ``end`` or ``next_batch`` +token to indicate the results after the returned set. + +In the following examples, 'START' and 'END' are placeholders to signify the +start and end of the data sets respectively. For example, if an endpoint had events E1 -> E15. The client wants the last 5 events and doesn't know any previous events:: @@ -1067,8 +1046,8 @@ events and doesn't know any previous events:: Another example: a public room list has rooms R1 -> R17. The client is showing 5 -rooms at a time on screen, and is on page 2. They want to -now show page 3 (rooms R11 -> 15):: +rooms at a time on screen, and is on page 2. They want to now show page 3 (rooms +R11 -> 15):: S E | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | stream token @@ -1086,20 +1065,17 @@ token from the initial request was '9' which corresponded to R10. When the 2nd request was made, R10 did not appear again, even though from=9 was specified. If you know the token, you already have the data. -Pagination Response -~~~~~~~~~~~~~~~~~~~ - -Responses to pagination requests MUST follow the format:: - - { - "chunk": [ ... , Responses , ... ], - "start" : $streamtoken, - "end" : $streamtoken - } - -Where $streamtoken is an opaque token which can be used in another query to -get the next set of results. The "start" and "end" keys can only be omitted if -the complete dataset is provided in "chunk". +Responses for pagination-capable endpoints SHOULD have a ``chunk`` array alongside +the applicable stream tokens to represent the result set. + +In general, when the end of a result set is reached the applicable stream token +will be excluded from the response. For example, if a user was backwards-paginating +events in a room they'd eventually reach the first event in the room. In this scenario, +the ``prev_batch`` token would be excluded from the response. Some paginated +endpoints are open-ended in one direction, such as endpoints which expose an event +stream for an active room. In this case, it is not possible for the client to reach +the true "end" of the data set and therefore should always be presented with a token +to keep moving forwards. .. _`filter`: From e49ed5d1ecce075a46fb137a7c8219eb96167bc5 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 31 Aug 2018 12:37:24 -0600 Subject: [PATCH 24/26] Changelog --- changelogs/client_server/newsfragments/1642.clarification | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/client_server/newsfragments/1642.clarification diff --git a/changelogs/client_server/newsfragments/1642.clarification b/changelogs/client_server/newsfragments/1642.clarification new file mode 100644 index 00000000..0ccb0f3c --- /dev/null +++ b/changelogs/client_server/newsfragments/1642.clarification @@ -0,0 +1 @@ +Clarify and generalise the language used for describing pagination. From f299fe023ac1784e37b609b640e60f5a602dca24 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 31 Aug 2018 12:51:31 -0600 Subject: [PATCH 25/26] English --- specification/client_server_api.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/specification/client_server_api.rst b/specification/client_server_api.rst index a329aa0c..cf5bc9ea 100644 --- a/specification/client_server_api.rst +++ b/specification/client_server_api.rst @@ -1017,16 +1017,16 @@ These datasets are not limited to events in a room (for example clients may want to paginate a list of rooms in addition to events within those rooms). Regardless of what is being paginated, there is a common approach which is used to give clients an easy way of selecting subsets of a potentially changing dataset. Each -endpoint that uses pagination may use different parameters, however the theme -amoung them is that they take a ``from`` and ``to`` token, and occasionally -a ``limit`` and ``dir`` to describe the direction to look in. Together, these -parameters describe the position in a data set, where ``from`` and ``to`` are -known as "stream tokens" matching the regular expression ``[a-zA-Z0-9.=_-]+``. -If supported, the ``dir`` defines the direction of events to return: either -forwards (``f``) or backwards (``b``). The response contains a ``start`` or -``prev_batch`` token which references the result set immediately prior to the -returned set. The response might additionally have an ``end`` or ``next_batch`` -token to indicate the results after the returned set. +endpoint that uses pagination may use different parameters. However the theme +among them is that they take a ``from`` and ``to`` token, and occasionally +a ``limit`` and ``dir``. Together, these parameters describe the position in a +data set, where ``from`` and ``to`` are known as "stream tokens" matching the +regular expression ``[a-zA-Z0-9.=_-]+``. If supported, the ``dir`` defines the +direction of events to return: either forwards (``f``) or backwards (``b``). +The response contains a ``start`` or ``prev_batch`` token which references the +result set immediately prior to the returned set. The response might additionally +have an ``end`` or ``next_batch`` token to indicate the results after the returned +set. In the following examples, 'START' and 'END' are placeholders to signify the start and end of the data sets respectively. From 835f5de387f5e09861d9065d7283815d9d099152 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 31 Aug 2018 14:22:07 -0600 Subject: [PATCH 26/26] Generalize the token name even more --- specification/client_server_api.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/specification/client_server_api.rst b/specification/client_server_api.rst index cf5bc9ea..549474af 100644 --- a/specification/client_server_api.rst +++ b/specification/client_server_api.rst @@ -1023,10 +1023,10 @@ a ``limit`` and ``dir``. Together, these parameters describe the position in a data set, where ``from`` and ``to`` are known as "stream tokens" matching the regular expression ``[a-zA-Z0-9.=_-]+``. If supported, the ``dir`` defines the direction of events to return: either forwards (``f``) or backwards (``b``). -The response contains a ``start`` or ``prev_batch`` token which references the -result set immediately prior to the returned set. The response might additionally -have an ``end`` or ``next_batch`` token to indicate the results after the returned -set. +The response may contain tokens that can be used for retrieving results before +or after the returned set. These tokens may be called `start` or `prev_batch` +for retrieving the previous result set, or `end`, `next_batch` or `next_token` +for retrieving the next result set. In the following examples, 'START' and 'END' are placeholders to signify the start and end of the data sets respectively.