| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750 |
- // ## End-to-End Encrypted Messages (Supplementary)
- //
- // This is a supplementary section to the corresponding structbuf section
- // with newer messages that use protobuf instead of structbuf. All defined
- // messages here follow the same logic.
- syntax = "proto3";
- package csp_e2e;
- option java_package = "ch.threema.protobuf.csp.e2e";
- option java_multiple_files = true;
- import "common.proto";
- // Metadata sent within a CSP payload `message-with-metadata-box` struct.
- message MessageMetadata {
- // Padding that is ignored by the receiver.
- // Recommended to be chosen such that the total length of padding + nickname
- // is at least 16 bytes. May be empty if the nickname is long enough.
- bytes padding = 1;
- // Unique message ID. Must match the message ID of the outer struct
- // (i.e. `message-with-metadata-box.message-id`).
- fixed64 message_id = 3;
- // Unix-ish timestamp in milliseconds for when the message has been created.
- //
- // Messages sent in a group must have the same timestamp for each group
- // member.
- uint64 created_at = 4;
- // Nickname
- //
- // Should be sent when the associate message requires _user profile
- // distribution_.
- //
- // When the user cleared its nickname, send an empty string. Do not send the
- // user's Threema ID (i.e. process data).
- //
- // Recommended to not exceed 32 grapheme clusters. Should not contain
- // whitespace characters at the beginning or the end of string.
- optional string nickname = 2;
- }
- // Edit an existing message (e.g. a text message or a media message caption).
- //
- // **Properties (1:1)**:
- // - Kind: 1:1
- // - Flags:
- // - `0x01`: Send push notification.
- // - User profile distribution: No
- // - Exempt from blocking: No
- // - Implicit _direct_ contact creation: No
- // - Protect against replay: Yes
- // - Unarchive: No
- // - Bump _last update_: No
- // - Reflect:
- // - Incoming: Yes
- // - Outgoing: Yes
- // - _Sent_ update: No
- // - Delivery receipts: No
- // - Reactions: No
- // - Edit applies to: N/A (obviously)
- // - Deletable by: N/A
- // - Include in history: Yes
- // - When rejected: N/A (ignored)
- // - Send to Threema Gateway ID group creator: N/A
- //
- // **Properties (Group)**:
- // - Kind: Group
- // - Flags:
- // - `0x01`: Send push notification.
- // - User profile distribution: No
- // - Exempt from blocking: No
- // - Implicit _direct_ contact creation: No
- // - Protect against replay: Yes
- // - Unarchive: No
- // - Bump _last update_: No
- // - Reflect:
- // - Incoming: Yes
- // - Outgoing: Yes
- // - _Sent_ update: No
- // - Delivery receipts: N/A
- // - Reactions: No
- // - Edit applies to: N/A (obviously)
- // - Deletable by: N/A
- // - Include in history: Yes
- // - When rejected: N/A (ignored)
- // - Send to Threema Gateway ID group creator: If capture is enabled
- //
- // The following steps must be invoked when the user wants to edit a 1:1
- // message:
- //
- // 1. If the sender or the receiver do not have `EDIT_MESSAGE_SUPPORT`, disallow
- // editing and abort these steps.
- // 2. Let `message` be the referred message.
- // 3. If the user is not the original sender of `message`, disallow editing and
- // abort these steps.
- // 4. If `message` has been sent (`sent-at`) more than 6 hours ago, disallow
- // editing and abort these steps.¹
- // 5. Allow the user to edit the referred message.
- //
- // The following steps must be invoked when the user wants to edit a group
- // message:
- //
- // 1. If the group is marked as _left_, disallow editing and abort these steps.
- // 2. If the sender or all of the group members do not have
- // `EDIT_MESSAGE_SUPPORT`, disallow editing and abort these steps.
- // 3. Let `message` be the referred message.
- // 4. If the user is not the original sender of `message`, disallow editing and
- // abort these steps.
- // 5. If the group is not a _notes_ group:
- // 1. If `message` has been sent (`sent-at`) more than 6 hours ago, disallow
- // editing and abort these steps.¹
- // 6. If any of the group members do not have `EDIT_MESSAGE_SUPPORT`, notify the
- // user that the affected contacts will not receive the edited content.
- // 7. Allow the user to edit the referred message.
- //
- // The following steps must be invoked when the user wants to submit an edited
- // 1:1 message.
- //
- // 1. If the sender or the receiver do not have `EDIT_MESSAGE_SUPPORT`, discard
- // the edited message and abort these steps.
- // 2. Run the _Common Edit Message Submit Preflight Steps_.
- // 3. Let `edited-at` be the current timestamp.
- // 4. Run the _1:1 Messages Submit Steps_ with `messages` set from the following
- // properties:
- // - `created-at` set to `edited-at`,
- // - to construct an `EditMessage` message.
- // 5. Edit the referred message as defined by the associated _Edit applies to_
- // property and add an indicator to the referred message, informing the user
- // that the referred message has been edited by the user at `edited-at`.
- //
- // The following steps must be invoked when the user wants to submit an edited
- // group message.
- //
- // 1. If the group is marked as _left_, discard the edited message and abort
- // these steps.
- // 2. If the sender or all of the group members do not have
- // `EDIT_MESSAGE_SUPPORT`, discard the edited message and abort these steps.
- // 3. Run the _Common Edit Message Submit Preflight Steps_.
- // 4. Let `edited-at` be the current timestamp.
- // 5. Run the _Group Messages Submit Steps_ with `messages` set from the
- // following properties:
- // - `created-at` set to `edited-at`,
- // - to construct an `EditMessage` message (wrapped by
- // [`group-member-container`](ref:e2e.group-member-container)).
- // 6. Edit the referred message as defined by the associated _Edit applies to_
- // property and add an indicator to the referred message, informing the user
- // that the referred message has been edited by the user at `edited-at`.
- //
- // The following steps are defined as the _Common Edit Message Submit Preflight
- // Steps_:
- //
- // 1. Lookup the message with `message_id` originally sent by the sender within
- // the associated conversation and let `message` be the result.
- // 2. If `message` is no longer defined, discard the edited message and abort
- // these steps.
- // 3. If the content of `message` is identical to the edited message, discard
- // the edited message and abort these steps.
- //
- // When reflected from another device as an incoming or outgoing 1:1 message:
- //
- // 1. Run the _Common Edit Message Receive Steps_.
- //
- // When receiving this message as a 1:1 message:
- //
- // 1. Run the _Common Edit Message Receive Steps_.
- //
- // When reflected from another device as an incoming or outgoing group message:
- //
- // 1. Run the _Common Edit Message Receive Steps_.
- //
- // When receiving this message as a group message (wrapped by
- // [`group-member-container`](ref:e2e.group-member-container)):
- //
- // 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the message
- // has been discarded, abort these steps.
- // 2. Run the _Common Edit Message Receive Steps_.
- //
- // The following steps are defined as the _Common Edit Message Receive Steps_:
- //
- // 1. Lookup the message with `message_id` originally sent by the sender within
- // the associated conversation and let `referred-message` be the result.
- // 2. If `referred-message` is not defined or the sender is not the original
- // sender of `referred-message`, discard the message and abort these steps.²
- // 3. If `referred-message` is not editable (see the associated _Edit applies
- // to_ property), discard the message and abort these steps.
- // 4. Edit `referred-message` as defined by the associated _Edit applies to_
- // property and add an indicator to `referred-message`, informing the user
- // that the message has been edited by the sender at the message's (the
- // `EditMessage`'s) `created-at`.
- //
- // ¹: For simplicity, the time constraint is applied on the sender side only.
- // The receiver will always accept a request to edit a message. This is deemed
- // acceptable considering this is not a security feature.
- //
- // ²: Implementations do not track the group member setup at the time a message
- // was received. Therefore, an edited message is always sent to the **current**
- // group member setup, including any group members that weren't part of the
- // group when the message was sent. However, any ordinary client will discard
- // `EditMessage` for unknown messages. This leak is not great but considered
- // acceptable for now.
- message EditMessage {
- // Unique ID of the referred message to be edited.
- fixed64 message_id = 1;
- // Text (or caption) to update the referred message with. Should be ≤ 6000
- // bytes.
- string text = 2;
- }
- // Remove an existing message.
- //
- // Note: This is a soft-security feature at best and it applies a best effort
- // approach, meaning that it relies on some level of good will on the receiving
- // end. A malicious receiver can easily persist a message prior to removal by
- // e.g. making a screenshot, forwarding it, changing the date, explicitly saving
- // it (if it contains media), etc.
- //
- // **Properties (1:1)**:
- // - Kind: 1:1
- // - Flags:
- // - `0x01`: Send push notification.
- // - User profile distribution: No
- // - Exempt from blocking: No
- // - Implicit _direct_ contact creation: No
- // - Protect against replay: Yes
- // - Unarchive: No
- // - Bump _last update_: No
- // - Reflect:
- // - Incoming: Yes
- // - Outgoing: Yes
- // - _Sent_ update: No
- // - Delivery receipts: No
- // - Reactions: No
- // - Edit applies to: N/A
- // - Deletable by: N/A (obviously)
- // - Include in history: Yes
- // - When rejected: N/A (ignored)
- // - Send to Threema Gateway ID group creator: N/A
- //
- // **Properties (Group)**:
- // - Kind: Group
- // - Flags:
- // - `0x01`: Send push notification.
- // - User profile distribution: No
- // - Exempt from blocking: No
- // - Implicit _direct_ contact creation: No
- // - Protect against replay: Yes
- // - Unarchive: No
- // - Bump _last update_: No
- // - Reflect:
- // - Incoming: Yes
- // - Outgoing: Yes
- // - _Sent_ update: No
- // - Delivery receipts: N/A
- // - Reactions: No
- // - Edit applies to: N/A
- // - Deletable by: N/A (obviously)
- // - Include in history: Yes
- // - When rejected: N/A (ignored)
- // - Send to Threema Gateway ID group creator: If capture is enabled
- //
- // The following steps must be invoked when the user wants to delete a 1:1
- // message:
- //
- // 1. If the sender or the receiver do not have `DELETE_MESSAGE_SUPPORT`,
- // disallow removal and abort these steps.
- // 2. Let `message` be the referred message.
- // 3. If the user is not the original sender of `message`, disallow removal and
- // abort these steps.
- // 4. If `message` has been sent (`sent-at`) more than 6 hours ago, disallow
- // removal and abort these steps.¹
- // 5. Let `deleted-at` be the current timestamp.
- // 6. Run the _1:1 Messages Submit Steps_ with `messages` set from the following
- // properties:
- // - `created-at` set to `deleted-at`,
- // - to construct a `DeleteMessage` message.
- // 7. Replace the referred message with a message informing the user that the
- // referred message of the user has been removed at `deleted-at`.²
- //
- // The following steps must be invoked when the user wants to delete a group
- // message.
- //
- // 1. If the group is marked as _left_, disallow removal and abort these steps.
- // 2. If the sender or all of the group members do not have
- // `DELETE_MESSAGE_SUPPORT`, disallow removal and abort these steps.
- // 3. Let `message` be the referred message.
- // 4. If the user is not the original sender of `message`, disallow removal and
- // abort these steps.
- // 5. If the group is not a _notes_ group:
- // 1. If `message` has been sent (`sent-at`) more than 6 hours ago, disallow
- // removal and abort these steps.¹
- // 6. Let `deleted-at` be the current timestamp.
- // 7. If any of the group members do not have `DELETE_MESSAGE_SUPPORT`, notify
- // the user that the affected contacts will continue to see the message.
- // 8. Run the _Group Messages Submit Steps_ with `messages` set from the
- // following properties:
- // - `created-at` set to `deleted-at`,
- // - to construct a `DeleteMessage` message (wrapped by
- // [`group-member-container`](ref:e2e.group-member-container)).
- // 9. Replace the referred message with a message informing the user that the
- // referred message of the user has been removed at `deleted-at`.²
- //
- // When reflected from another device as an incoming or outgoing 1:1 message:
- //
- // 1. Run the _Common Delete Message Receive Steps_.
- //
- // When receiving this message as a 1:1 message:
- //
- // 1. Run the _Common Delete Message Receive Steps_.
- //
- // When reflected from another device as an incoming or outgoing group message:
- //
- // 1. Run the _Common Delete Message Receive Steps_.
- //
- // When receiving this message as a group message (wrapped by
- // [`group-member-container`](ref:e2e.group-member-container)):
- //
- // 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the message
- // has been discarded, abort these steps.
- // 2. Run the _Common Delete Message Receive Steps_.
- //
- // The following steps are defined as the _Common Delete Message Receive Steps_:
- //
- // 1. Lookup the message with `message_id` originally sent by the sender within
- // the associated conversation and let `referred-message` be the result.
- // 2. If `referred-message` is not defined or the sender is not the original
- // sender of `referred-message`, discard the message and abort these steps.
- // 3. If `referred-message` is not deletable (see the associated _Deletable by_
- // property), discard the message and abort these steps.
- // 4. Replace `referred-message` with a message informing the user that the
- // message of the sender has been removed at the message's (the
- // `DeleteMessage`'s) `created-at`.²
- //
- // ¹: For simplicity, the time constraint is applied on the sender side only.
- // The receiver will always accept a request to delete a message. This is deemed
- // acceptable considering this is just barely a soft-security feature.
- //
- // ²: All references to a removed message (e.g. quotes) must be updated as well,
- // so that the message content is no longer visible. An implementation should
- // also try to withdraw or update any notification created for a removed
- // message.
- message DeleteMessage {
- // Unique ID of the referred message to be removed.
- fixed64 message_id = 1;
- }
- // Announces and immediately starts a group call.
- //
- // **Properties**:
- // - Kind: Group
- // - Flags:
- // - `0x01`: Send push notification.
- // - User profile distribution: Yes
- // - Exempt from blocking: Yes
- // - Implicit _direct_ contact creation: No
- // - Protect against replay: Yes
- // - Unarchive: TODO(SE-508)
- // - Bump _last update_: TODO(SE-508)
- // - Reflect:
- // - Incoming: Yes
- // - Outgoing: Yes
- // - _Sent_ update: No
- // - Delivery receipts: N/A
- // - Reactions: No
- // - When rejected: N/A¹
- // - Edit applies to: N/A
- // - Deletable by: N/A
- // - Include in history: Yes
- // - Send to Threema Gateway ID group creator: If capture is enabled
- //
- // ¹: For the group creator it will be handled as if `group-sync-request` was
- // received, re-sending a `GroupCallStart` if still ongoing, implicitly
- // triggered by FS `Reject` receive steps.
- //
- // When the user wants to create a new group call or join an existing group
- // call, run the steps outlined in the _Create or Join_ section of the Group
- // Call Protocol.
- //
- // When reflected from another device as an incoming or outgoing message:
- //
- // 1. Run the _Common Group Call Start Receive Steps_.
- //
- // When receiving this message:
- //
- // 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the message
- // has been discarded, abort these steps.
- // 2. Run the _Common Group Call Start Receive Steps_.
- //
- // The following steps are defined as the _Common Group Call Start Receive
- // Steps_:
- //
- // 1. If the hostname of `sfu_base_url` does not use the scheme `https` or does
- // not end with one of the set of [_Allowed SFU Hostname
- // Suffixes_](ref:group-calls#obtain-sfu-information), log a warning, discard
- // the message and abort these steps.
- // 2. Let `running` be the list of group calls that are currently considered
- // running within the group.
- // 3. If another call with the same GCK exists in `running`, log a warning,
- // discard the message and abort these steps.
- // 4. Add the received call to the list of group calls that are currently
- // considered running (even if `protocol_version` is unsupported¹).
- // 5. Start a task to run the _Group Call Refresh Steps_.²
- //
- // ¹: Adding unsupported `protocol_version`s allows the user to join an ongoing
- // call after an app update where support for `protocol_version` has been
- // added.
- //
- // ²: This ensures that the user automatically switches to the chosen call if it
- // is currently participating in a group call of this group.
- message GroupCallStart {
- // Protocol version used for group calls of this group. The current version
- // number is `1`.
- //
- // Note: This is a _major_ version and may only be increased in case of
- // breaking changes due to the significant UX impact this has when running the
- // _Common Group Receive Steps_ (i.e. only calls with supported protocol
- // versions can be _chosen_).
- uint32 protocol_version = 1;
- // The secret Group Call Key (`GCK`) used for this call.
- bytes gck = 2;
- // The base URL of the SFU, used to join or peek the call.
- string sfu_base_url = 3;
- }
- // React to a message.
- //
- // **Properties (1:1)**:
- // - Kind: 1:1
- // - Flags:
- // - `0x01`: Send push notification.
- // - User profile distribution: Yes
- // - Exempt from blocking: No
- // - Implicit _direct_ contact creation: No
- // - Protect against replay: Yes
- // - Reflect:
- // - Incoming: Yes
- // - Outgoing: Yes
- // - _Sent_ update: No
- // - Delivery receipts: No
- // - Reactions: No, that would be silly!
- // - When rejected: N/A (ignored)
- // - Edit applies to: N/A (can withdraw and apply with another `Reaction`)
- // - Deletable by: N/A (can withdraw with another `Reaction`)
- // - Include in history: Yes
- // - Send to Threema Gateway ID group creator: N/A
- //
- // **Properties (Group)**:
- // - Kind: 1:1
- // - Flags:
- // - `0x01`: Send push notification.
- // - User profile distribution: Yes
- // - Exempt from blocking: No
- // - Implicit _direct_ contact creation: No
- // - Protect against replay: Yes
- // - Reflect:
- // - Incoming: Yes
- // - Outgoing: Yes
- // - _Sent_ update: No
- // - Delivery receipts: N/A
- // - Reactions: No, that would be silly!
- // - When rejected: N/A (ignored)
- // - Edit applies to: N/A (can withdraw and apply with another `Reaction`)
- // - Deletable by: N/A (can withdraw with another `Reaction`)
- // - Include in history: Yes
- // - Send to Threema Gateway ID group creator: If capture is enabled
- //
- // When the user submits a reaction in a 1:1 conversation:
- //
- // 1. Let `reaction` be the reaction to be applied to or withdrawn from a
- // referred message which must contain a single fully-qualified [emoji
- // codepoint sequence that is part of the currently supported Unicode
- // standard][emoji-test.txt].
- // 2. Run the _Legacy Reaction Mapping Steps_ with `reaction` and let
- // `legacy-reaction` be the result.
- // 3. If `legacy-reaction` is not defined and the sender or the receiver does
- // not have `REACTION_SUPPORT`, log a warning and abort these steps.¹
- // 4. Let `reacted-at` be the current timestamp.
- // 5. If both sender and receiver have `REACTION_SUPPORT`, run the _1:1 Messages
- // Submit Steps_ with `messages` set from the following properties:
- // - `created-at` set to `reacted-at`,
- // - to construct a `Reaction` message from `reaction`.
- // 6. If the sender or the receiver does not have `REACTION_SUPPORT`, run the
- // _1:1 Messages Submit Steps_ with `messages` set from the following
- // properties:
- // - `created-at` set to `reacted-at`,
- // - to construct the `legacy-reaction`.
- // 7. Apply `reaction` (i.e. apply or withdraw) to the referred message with the
- // `reacted-at` timestamp.
- //
- // When the user submits a reaction in a group conversation:
- //
- // 1. Let `reaction` be the reaction to be applied to or withdrawn from a
- // referred message which must contain a single fully-qualified [emoji
- // codepoint sequence that is part of the currently supported Unicode
- // standard][emoji-test.txt].
- // 2. Run the _Legacy Reaction Mapping Steps_ with `reaction` and let
- // `legacy-reaction` be the result.
- // 3. If `legacy-reaction` is not defined:
- // 1. If the sender does not have `REACTION_SUPPORT`, log a warning and abort
- // these steps.²
- // 2. If all of the group members do not have `REACTION_SUPPORT`, log a
- // warning and and abort these steps.²
- // 3. If any of the group members do not have `REACTION_SUPPORT`, notify the
- // user that the affected contacts will not receive the reaction.
- // 4. Let `reacted-at` be the current timestamp.
- // 5. Run the _Group Messages Submit Steps_ with `messages` set from the
- // following properties:
- // - `created-at` set to `reacted-at`,
- // - to construct a _canonical_ `Reaction` message from `reaction`,
- // - to construct a _specific_ message in the following way:
- // 1. Let `receiver` be the specific receiver.
- // 2. If the `receiver` does not have `REACTION_SUPPORT` and
- // `legacy-reaction` is defined, return the `legacy-reaction` (wrapped
- // by [`group-member-container`](ref:e2e.group-member-container)).
- // 3. Construct and return the _canonical_ `Reaction` message from
- // `reaction` (wrapped by
- // [`group-member-container`](ref:e2e.group-member-container)).³
- // 6. Apply `reaction` (i.e. apply or withdraw) to the referred message with the
- // `reacted-at` timestamp.
- //
- // The following steps are defined as the _Legacy Reaction Mapping Steps_:
- //
- // 1. If `action` is of variant `apply`:
- // 1. If `action.apply` equals one of the following codepoint sequences,
- // return a `e2e.delivery-receipt` of type _acknowledge_ (0x03):
- // - `1F44D` (👍)
- // - `1F44D 1F3FB` (👍🏻)
- // - `1F44D 1F3FC` (👍🏼)
- // - `1F44D 1F3FD` (👍🏽)
- // - `1F44D 1F3FE` (👍🏾)
- // - `1F44D 1F3FF` (👍🏿)
- // 2. If `action.apply` equals one of the following codepoint sequences,
- // return a `e2e.delivery-receipt` of type _decline_ (0x04):
- // - `1F44E` (👎)
- // - `1F44E 1F3FB` (👎🏻)
- // - `1F44E 1F3FC` (👎🏼)
- // - `1F44E 1F3FD` (👎🏽)
- // - `1F44E 1F3FE` (👎🏾)
- // - `1F44E 1F3FF` (👎🏿)
- // 2. Return no message.
- //
- // When reflected from another device as an incoming or outgoing 1:1 message:
- //
- // 1. Run the _Common Reaction Receive Steps_.
- //
- // When receiving this message:
- //
- // 1. Run the _Common Reaction Receive Steps_.
- //
- // When receiving this message (wrapped by
- // [`group-member-container`](ref:e2e.group-member-container)):
- //
- // 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the reaction
- // message has been discarded, abort these steps.
- // 1. Run the _Common Reaction Receive Steps_.
- //
- // The following steps are defined as the _Common Reaction Receive Steps_:
- //
- // 1. Lookup the referred message with `message_id` within the associated
- // conversation and let `referred-message` be the result.
- // 2. If `referred-message` is not defined, discard the message and abort these
- // steps.
- // 3. If `referred-message` is not reactable (see the associated _Reactions_
- // property), discard the message and abort these steps.
- // 4. If `action` is of variant `apply`:
- // 1. If `apply` contains more than 64 bytes, discard the message and abort
- // these steps.
- // 2. Decode `apply` to a UTF-8 string. If the string is empty, discard the
- // message and abort these steps.
- // 3. Apply (or re-apply) the resulting emoji from the sender to
- // `referred-message` with the message's (the `Reaction`'s) `created-at`
- // timestamp used for the time of reaction.⁴⁵
- // 5. If `action` is of variant `withdraw`:
- // 1. If `withdraw` contains more than 64 bytes, discard the message and
- // abort these steps.
- // 2. Decode `withdraw` to a UTF-8 string. If the string is empty, discard
- // the message and abort these steps.
- // 3. Remove the resulting emoji reaction from the sender for `message`.⁴⁵
- //
- // ¹: The UI should not allow to create non-legacy reactions in 1:1
- // conversations with a sender or receiver that does not have
- // `REACTION_SUPPORT`.
- //
- // ²: The UI should not allow to create non-legacy reactions in group
- // conversations with a sender that does not have `REACTION_SUPPORT` or when all
- // other group members don't have `REACTION_SUPPORT`.
- //
- // ³: In case the reaction could not be mapped to a legacy reaction, this
- // results in a `Reaction` message being sent to group members that currently do
- // not support reactions. This is intentional.
- //
- // ⁴: Note that the _apply_ mechanism is additive, meaning multiple reactions
- // from the same sender are allowed on a single message. This is why the
- // _withdraw_ mechanism is needed which removes a specific reaction. On the
- // other hand, a deprecated `e2e.delivery-receipt` will replace all existing
- // reactions of the sender at once (including these new-style reactions).
- //
- // ⁵: The UI should display a placeholder (�) for unknown emojis, meaining those
- // which are not a single fully-qualified [emoji codepoint sequence that is part
- // of the currently supported Unicode standard][emoji-test.txt]. But the
- // individual code sequences still have individual display buckets.
- //
- // [emoji-test.txt]: https://www.unicode.org/Public/emoji/latest/emoji-test.txt
- message Reaction {
- // Unique ID of the referred message.
- fixed64 message_id = 1;
- // A single emoji reaction to be applied or withdrawn.
- oneof action {
- // Apply a new emoji reaction.
- bytes apply = 2;
- // Withdraw a specific emoji reaction.
- bytes withdraw = 3;
- }
- }
- // Request joining a group.
- //
- // This message is sent to the administrator of a group. The required
- // information is provided by a `GroupInvite` URL payload.
- //
- // **Properties**:
- // - Kind: 1:1
- // - Flags:
- // - `0x01`: Send push notification.
- // - User profile distribution: Yes
- // - Exempt from blocking: Yes
- // - Implicit _direct_ contact creation: Yes
- // - Protect against replay: Yes
- // - Reflect:
- // - Incoming: Yes
- // - Outgoing: Yes
- // - _Sent_ update: No
- // - Delivery receipts: No
- // - Reactions: No
- // - When rejected: N/A (ignored)
- // - Edit applies to: N/A
- // - Deletable by: User only
- // - Include in history: No
- // - Send to Threema Gateway ID group creator: N/A
- //
- // When receiving this message:
- //
- // 1. Look up the corresponding group invitation by the token.
- // 2. If the group invitation could not be found, discard the message and abort
- // these steps.
- // 3. If the sender is already part of the group, send an accept response and
- // then respond as if the sender had sent a `group-sync-request` (i.e. send a
- // `group-setup`, `group-name`, etc.). Finally, abort these steps.
- // 4. If the group name does not match the name in the originally sent group
- // invitation, discard the message and abort these steps.
- // 5. If the group invitation has expired, send the respective response and
- // abort these steps.
- // 6. If the group invitation requires the admin to accept the request, show
- // this information in the user interface and pause these steps until the
- // user manually confirmed of rejected the request. Note that the date of the
- // decision is allowed to extend beyond the expiration date of the group
- // invitation. Continue with the following sub-steps once the user made a
- // decision on the request:
- // 1. If the user manually rejected the request, send the respective
- // response and abort these steps.
- // 7. If the group is full, send the respective response and abort these steps.
- // 8. Send an accept response.
- // 9. Add the sender of the group invitation request to the group and follow the
- // group protocol from there.
- message GroupJoinRequest {
- // The group invite token, 16 bytes
- bytes token = 1;
- // The group name from the group invite URL
- string group_name = 2;
- // A message for the group administrator, e.g. for identification purposes
- //
- // The message helps the administrator to decide whether or not to accept a
- // join request.
- //
- // Should be requested by the user interface for invitations that require
- // manual confirmation by the administrator. Should not be requested in case
- // the invitation will be automatically accepted.
- string message = 3;
- }
- // Response sent by the admin of a group towards a sender of a valid group join
- // request.
- //
- // **Properties**:
- // - Kind: 1:1
- // - Flags: None
- // - User profile distribution: Yes
- // - Exempt from blocking: Yes
- // - Implicit _direct_ contact creation: Yes
- // - Protect against replay: Yes
- // - Reflect:
- // - Incoming: Yes
- // - Outgoing: Yes
- // - _Sent_ update: No
- // - Delivery receipts: No
- // - Reactions: No
- // - When rejected: N/A (ignored)
- // - Edit applies to: N/A
- // - Deletable by: N/A
- // - Include in history: Yes
- // - Send to Threema Gateway ID group creator: N/A
- //
- // When receiving this message:
- //
- // 1. Look up the corresponding group join request by the token and the
- // sender's Threema ID as the administrator's Threema ID.
- // 2. If the group join request could not be found, discard the message and
- // abort these steps.
- // 3. Mark the group join request as accepted or (automatically) rejected by
- // the given response type.
- // 4. If the group join request has been accepted, remember the group id in
- // order to be able to map an incoming `group-setup` to the group.
- message GroupJoinResponse {
- // The group invite token, 16 bytes
- bytes token = 1;
- // Response of the admin
- message Response {
- // Accept a group invite request
- message Accept {
- // Group ID (little-endian) as chosen by the group creator
- //
- // Note: Combined with the Threema ID of the administrator, this forms the
- // `GroupIdentity`.
- fixed64 group_id = 1;
- }
- oneof response {
- // Accept a group invite request
- Accept accept = 1;
- // Token of a group invitation expired
- common.Unit expired = 2;
- // Group invitation cannot be accepted due to the group being full
- common.Unit group_full = 3;
- // The administrator explicitly rejects the invitation request
- common.Unit reject = 4;
- }
- }
- Response response = 2;
- }
|