csp-e2e.proto 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. // ## End-to-End Encrypted Messages (Supplementary)
  2. //
  3. // This is a supplementary section to the corresponding structbuf section
  4. // with newer messages that use protobuf instead of structbuf. All defined
  5. // messages here follow the same logic.
  6. syntax = "proto3";
  7. package csp_e2e;
  8. option java_package = "ch.threema.protobuf.csp.e2e";
  9. option java_multiple_files = true;
  10. import "common.proto";
  11. // Metadata sent within a CSP payload `message-with-metadata-box` struct.
  12. message MessageMetadata {
  13. // Padding that is ignored by the receiver.
  14. // Recommended to be chosen such that the total length of padding + nickname
  15. // is at least 16 bytes. May be empty if the nickname is long enough.
  16. bytes padding = 1;
  17. // Unique message ID. Must match the message ID of the outer struct
  18. // (i.e. `message-with-metadata-box.message-id`).
  19. fixed64 message_id = 3;
  20. // Unix-ish timestamp in milliseconds for when the message has been created.
  21. //
  22. // Messages sent in a group must have the same timestamp for each group
  23. // member.
  24. uint64 created_at = 4;
  25. // Nickname
  26. //
  27. // Should be sent when the associate message requires _user profile
  28. // distribution_.
  29. //
  30. // When the user cleared its nickname, send an empty string. Do not send the
  31. // user's Threema ID (i.e. process data).
  32. //
  33. // Recommended to not exceed 32 grapheme clusters. Should not contain
  34. // whitespace characters at the beginning or the end of string.
  35. optional string nickname = 2;
  36. }
  37. // Edit an existing message (e.g. a text message or a media message caption).
  38. //
  39. // **Properties (1:1)**:
  40. // - Kind: 1:1
  41. // - Flags:
  42. // - `0x01`: Send push notification.
  43. // - User profile distribution: No
  44. // - Exempt from blocking: No
  45. // - Implicit _direct_ contact creation: No
  46. // - Protect against replay: Yes
  47. // - Unarchive: No
  48. // - Bump _last update_: No
  49. // - Reflect:
  50. // - Incoming: Yes
  51. // - Outgoing: Yes
  52. // - _Sent_ update: No
  53. // - Delivery receipts: No
  54. // - Reactions: No
  55. // - Edit applies to: N/A (obviously)
  56. // - Deletable by: N/A
  57. // - Include in history: Yes
  58. // - When rejected: N/A (ignored)
  59. // - Send to Threema Gateway ID group creator: N/A
  60. //
  61. // **Properties (Group)**:
  62. // - Kind: Group
  63. // - Flags:
  64. // - `0x01`: Send push notification.
  65. // - User profile distribution: No
  66. // - Exempt from blocking: No
  67. // - Implicit _direct_ contact creation: No
  68. // - Protect against replay: Yes
  69. // - Unarchive: No
  70. // - Bump _last update_: No
  71. // - Reflect:
  72. // - Incoming: Yes
  73. // - Outgoing: Yes
  74. // - _Sent_ update: No
  75. // - Delivery receipts: N/A
  76. // - Reactions: No
  77. // - Edit applies to: N/A (obviously)
  78. // - Deletable by: N/A
  79. // - Include in history: Yes
  80. // - When rejected: N/A (ignored)
  81. // - Send to Threema Gateway ID group creator: If capture is enabled
  82. //
  83. // The following steps must be invoked when the user wants to edit a 1:1
  84. // message:
  85. //
  86. // 1. If the sender or the receiver do not have `EDIT_MESSAGE_SUPPORT`, disallow
  87. // editing and abort these steps.
  88. // 2. Let `message` be the referred message.
  89. // 3. If the user is not the original sender of `message`, disallow editing and
  90. // abort these steps.
  91. // 4. If `message` has been sent (`sent-at`) more than 6 hours ago, disallow
  92. // editing and abort these steps.¹
  93. // 5. Allow the user to edit the referred message.
  94. //
  95. // The following steps must be invoked when the user wants to edit a group
  96. // message:
  97. //
  98. // 1. If the group is marked as _left_, disallow editing and abort these steps.
  99. // 2. If the sender or all of the group members do not have
  100. // `EDIT_MESSAGE_SUPPORT`, disallow editing and abort these steps.
  101. // 3. Let `message` be the referred message.
  102. // 4. If the user is not the original sender of `message`, disallow editing and
  103. // abort these steps.
  104. // 5. If the group is not a _notes_ group:
  105. // 1. If `message` has been sent (`sent-at`) more than 6 hours ago, disallow
  106. // editing and abort these steps.¹
  107. // 6. If any of the group members do not have `EDIT_MESSAGE_SUPPORT`, notify the
  108. // user that the affected contacts will not receive the edited content.
  109. // 7. Allow the user to edit the referred message.
  110. //
  111. // The following steps must be invoked when the user wants to submit an edited
  112. // 1:1 message.
  113. //
  114. // 1. If the sender or the receiver do not have `EDIT_MESSAGE_SUPPORT`, discard
  115. // the edited message and abort these steps.
  116. // 2. Run the _Common Edit Message Submit Preflight Steps_.
  117. // 3. Let `edited-at` be the current timestamp.
  118. // 4. Run the _1:1 Messages Submit Steps_ with `messages` set from the following
  119. // properties:
  120. // - `created-at` set to `edited-at`,
  121. // - to construct an `EditMessage` message.
  122. // 5. Edit the referred message as defined by the associated _Edit applies to_
  123. // property and add an indicator to the referred message, informing the user
  124. // that the referred message has been edited by the user at `edited-at`.
  125. //
  126. // The following steps must be invoked when the user wants to submit an edited
  127. // group message.
  128. //
  129. // 1. If the group is marked as _left_, discard the edited message and abort
  130. // these steps.
  131. // 2. If the sender or all of the group members do not have
  132. // `EDIT_MESSAGE_SUPPORT`, discard the edited message and abort these steps.
  133. // 3. Run the _Common Edit Message Submit Preflight Steps_.
  134. // 4. Let `edited-at` be the current timestamp.
  135. // 5. Run the _Group Messages Submit Steps_ with `messages` set from the
  136. // following properties:
  137. // - `created-at` set to `edited-at`,
  138. // - to construct an `EditMessage` message (wrapped by
  139. // [`group-member-container`](ref:e2e.group-member-container)).
  140. // 6. Edit the referred message as defined by the associated _Edit applies to_
  141. // property and add an indicator to the referred message, informing the user
  142. // that the referred message has been edited by the user at `edited-at`.
  143. //
  144. // The following steps are defined as the _Common Edit Message Submit Preflight
  145. // Steps_:
  146. //
  147. // 1. Lookup the message with `message_id` originally sent by the sender within
  148. // the associated conversation and let `message` be the result.
  149. // 2. If `message` is no longer defined, discard the edited message and abort
  150. // these steps.
  151. // 3. If the content of `message` is identical to the edited message, discard
  152. // the edited message and abort these steps.
  153. //
  154. // When reflected from another device as an incoming or outgoing 1:1 message:
  155. //
  156. // 1. Run the _Common Edit Message Receive Steps_.
  157. //
  158. // When receiving this message as a 1:1 message:
  159. //
  160. // 1. Run the _Common Edit Message Receive Steps_.
  161. //
  162. // When reflected from another device as an incoming or outgoing group message:
  163. //
  164. // 1. Run the _Common Edit Message Receive Steps_.
  165. //
  166. // When receiving this message as a group message (wrapped by
  167. // [`group-member-container`](ref:e2e.group-member-container)):
  168. //
  169. // 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the message
  170. // has been discarded, abort these steps.
  171. // 2. Run the _Common Edit Message Receive Steps_.
  172. //
  173. // The following steps are defined as the _Common Edit Message Receive Steps_:
  174. //
  175. // 1. Lookup the message with `message_id` originally sent by the sender within
  176. // the associated conversation and let `referred-message` be the result.
  177. // 2. If `referred-message` is not defined or the sender is not the original
  178. // sender of `referred-message`, discard the message and abort these steps.²
  179. // 3. If `referred-message` is not editable (see the associated _Edit applies
  180. // to_ property), discard the message and abort these steps.
  181. // 4. Edit `referred-message` as defined by the associated _Edit applies to_
  182. // property and add an indicator to `referred-message`, informing the user
  183. // that the message has been edited by the sender at the message's (the
  184. // `EditMessage`'s) `created-at`.
  185. //
  186. // ¹: For simplicity, the time constraint is applied on the sender side only.
  187. // The receiver will always accept a request to edit a message. This is deemed
  188. // acceptable considering this is not a security feature.
  189. //
  190. // ²: Implementations do not track the group member setup at the time a message
  191. // was received. Therefore, an edited message is always sent to the **current**
  192. // group member setup, including any group members that weren't part of the
  193. // group when the message was sent. However, any ordinary client will discard
  194. // `EditMessage` for unknown messages. This leak is not great but considered
  195. // acceptable for now.
  196. message EditMessage {
  197. // Unique ID of the referred message to be edited.
  198. fixed64 message_id = 1;
  199. // Text (or caption) to update the referred message with. Should be ≤ 6000
  200. // bytes.
  201. string text = 2;
  202. }
  203. // Remove an existing message.
  204. //
  205. // Note: This is a soft-security feature at best and it applies a best effort
  206. // approach, meaning that it relies on some level of good will on the receiving
  207. // end. A malicious receiver can easily persist a message prior to removal by
  208. // e.g. making a screenshot, forwarding it, changing the date, explicitly saving
  209. // it (if it contains media), etc.
  210. //
  211. // **Properties (1:1)**:
  212. // - Kind: 1:1
  213. // - Flags:
  214. // - `0x01`: Send push notification.
  215. // - User profile distribution: No
  216. // - Exempt from blocking: No
  217. // - Implicit _direct_ contact creation: No
  218. // - Protect against replay: Yes
  219. // - Unarchive: No
  220. // - Bump _last update_: No
  221. // - Reflect:
  222. // - Incoming: Yes
  223. // - Outgoing: Yes
  224. // - _Sent_ update: No
  225. // - Delivery receipts: No
  226. // - Reactions: No
  227. // - Edit applies to: N/A
  228. // - Deletable by: N/A (obviously)
  229. // - Include in history: Yes
  230. // - When rejected: N/A (ignored)
  231. // - Send to Threema Gateway ID group creator: N/A
  232. //
  233. // **Properties (Group)**:
  234. // - Kind: Group
  235. // - Flags:
  236. // - `0x01`: Send push notification.
  237. // - User profile distribution: No
  238. // - Exempt from blocking: No
  239. // - Implicit _direct_ contact creation: No
  240. // - Protect against replay: Yes
  241. // - Unarchive: No
  242. // - Bump _last update_: No
  243. // - Reflect:
  244. // - Incoming: Yes
  245. // - Outgoing: Yes
  246. // - _Sent_ update: No
  247. // - Delivery receipts: N/A
  248. // - Reactions: No
  249. // - Edit applies to: N/A
  250. // - Deletable by: N/A (obviously)
  251. // - Include in history: Yes
  252. // - When rejected: N/A (ignored)
  253. // - Send to Threema Gateway ID group creator: If capture is enabled
  254. //
  255. // The following steps must be invoked when the user wants to delete a 1:1
  256. // message:
  257. //
  258. // 1. If the sender or the receiver do not have `DELETE_MESSAGE_SUPPORT`,
  259. // disallow removal and abort these steps.
  260. // 2. Let `message` be the referred message.
  261. // 3. If the user is not the original sender of `message`, disallow removal and
  262. // abort these steps.
  263. // 4. If `message` has been sent (`sent-at`) more than 6 hours ago, disallow
  264. // removal and abort these steps.¹
  265. // 5. Let `deleted-at` be the current timestamp.
  266. // 6. Run the _1:1 Messages Submit Steps_ with `messages` set from the following
  267. // properties:
  268. // - `created-at` set to `deleted-at`,
  269. // - to construct a `DeleteMessage` message.
  270. // 7. Replace the referred message with a message informing the user that the
  271. // referred message of the user has been removed at `deleted-at`.²
  272. //
  273. // The following steps must be invoked when the user wants to delete a group
  274. // message.
  275. //
  276. // 1. If the group is marked as _left_, disallow removal and abort these steps.
  277. // 2. If the sender or all of the group members do not have
  278. // `DELETE_MESSAGE_SUPPORT`, disallow removal and abort these steps.
  279. // 3. Let `message` be the referred message.
  280. // 4. If the user is not the original sender of `message`, disallow removal and
  281. // abort these steps.
  282. // 5. If the group is not a _notes_ group:
  283. // 1. If `message` has been sent (`sent-at`) more than 6 hours ago, disallow
  284. // removal and abort these steps.¹
  285. // 6. Let `deleted-at` be the current timestamp.
  286. // 7. If any of the group members do not have `DELETE_MESSAGE_SUPPORT`, notify
  287. // the user that the affected contacts will continue to see the message.
  288. // 8. Run the _Group Messages Submit Steps_ with `messages` set from the
  289. // following properties:
  290. // - `created-at` set to `deleted-at`,
  291. // - to construct a `DeleteMessage` message (wrapped by
  292. // [`group-member-container`](ref:e2e.group-member-container)).
  293. // 9. Replace the referred message with a message informing the user that the
  294. // referred message of the user has been removed at `deleted-at`.²
  295. //
  296. // When reflected from another device as an incoming or outgoing 1:1 message:
  297. //
  298. // 1. Run the _Common Delete Message Receive Steps_.
  299. //
  300. // When receiving this message as a 1:1 message:
  301. //
  302. // 1. Run the _Common Delete Message Receive Steps_.
  303. //
  304. // When reflected from another device as an incoming or outgoing group message:
  305. //
  306. // 1. Run the _Common Delete Message Receive Steps_.
  307. //
  308. // When receiving this message as a group message (wrapped by
  309. // [`group-member-container`](ref:e2e.group-member-container)):
  310. //
  311. // 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the message
  312. // has been discarded, abort these steps.
  313. // 2. Run the _Common Delete Message Receive Steps_.
  314. //
  315. // The following steps are defined as the _Common Delete Message Receive Steps_:
  316. //
  317. // 1. Lookup the message with `message_id` originally sent by the sender within
  318. // the associated conversation and let `referred-message` be the result.
  319. // 2. If `referred-message` is not defined or the sender is not the original
  320. // sender of `referred-message`, discard the message and abort these steps.
  321. // 3. If `referred-message` is not deletable (see the associated _Deletable by_
  322. // property), discard the message and abort these steps.
  323. // 4. Replace `referred-message` with a message informing the user that the
  324. // message of the sender has been removed at the message's (the
  325. // `DeleteMessage`'s) `created-at`.²
  326. //
  327. // ¹: For simplicity, the time constraint is applied on the sender side only.
  328. // The receiver will always accept a request to delete a message. This is deemed
  329. // acceptable considering this is just barely a soft-security feature.
  330. //
  331. // ²: All references to a removed message (e.g. quotes) must be updated as well,
  332. // so that the message content is no longer visible. An implementation should
  333. // also try to withdraw or update any notification created for a removed
  334. // message.
  335. message DeleteMessage {
  336. // Unique ID of the referred message to be removed.
  337. fixed64 message_id = 1;
  338. }
  339. // Announces and immediately starts a group call.
  340. //
  341. // **Properties**:
  342. // - Kind: Group
  343. // - Flags:
  344. // - `0x01`: Send push notification.
  345. // - User profile distribution: Yes
  346. // - Exempt from blocking: Yes
  347. // - Implicit _direct_ contact creation: No
  348. // - Protect against replay: Yes
  349. // - Unarchive: TODO(SE-508)
  350. // - Bump _last update_: TODO(SE-508)
  351. // - Reflect:
  352. // - Incoming: Yes
  353. // - Outgoing: Yes
  354. // - _Sent_ update: No
  355. // - Delivery receipts: N/A
  356. // - Reactions: No
  357. // - When rejected: N/A¹
  358. // - Edit applies to: N/A
  359. // - Deletable by: N/A
  360. // - Include in history: Yes
  361. // - Send to Threema Gateway ID group creator: If capture is enabled
  362. //
  363. // ¹: For the group creator it will be handled as if `group-sync-request` was
  364. // received, re-sending a `GroupCallStart` if still ongoing, implicitly
  365. // triggered by FS `Reject` receive steps.
  366. //
  367. // When the user wants to create a new group call or join an existing group
  368. // call, run the steps outlined in the _Create or Join_ section of the Group
  369. // Call Protocol.
  370. //
  371. // When reflected from another device as an incoming or outgoing message:
  372. //
  373. // 1. Run the _Common Group Call Start Receive Steps_.
  374. //
  375. // When receiving this message:
  376. //
  377. // 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the message
  378. // has been discarded, abort these steps.
  379. // 2. Run the _Common Group Call Start Receive Steps_.
  380. //
  381. // The following steps are defined as the _Common Group Call Start Receive
  382. // Steps_:
  383. //
  384. // 1. If the hostname of `sfu_base_url` does not use the scheme `https` or does
  385. // not end with one of the set of [_Allowed SFU Hostname
  386. // Suffixes_](ref:group-calls#obtain-sfu-information), log a warning, discard
  387. // the message and abort these steps.
  388. // 2. Let `running` be the list of group calls that are currently considered
  389. // running within the group.
  390. // 3. If another call with the same GCK exists in `running`, log a warning,
  391. // discard the message and abort these steps.
  392. // 4. Add the received call to the list of group calls that are currently
  393. // considered running (even if `protocol_version` is unsupported¹).
  394. // 5. Start a task to run the _Group Call Refresh Steps_.²
  395. //
  396. // ¹: Adding unsupported `protocol_version`s allows the user to join an ongoing
  397. // call after an app update where support for `protocol_version` has been
  398. // added.
  399. //
  400. // ²: This ensures that the user automatically switches to the chosen call if it
  401. // is currently participating in a group call of this group.
  402. message GroupCallStart {
  403. // Protocol version used for group calls of this group. The current version
  404. // number is `1`.
  405. //
  406. // Note: This is a _major_ version and may only be increased in case of
  407. // breaking changes due to the significant UX impact this has when running the
  408. // _Common Group Receive Steps_ (i.e. only calls with supported protocol
  409. // versions can be _chosen_).
  410. uint32 protocol_version = 1;
  411. // The secret Group Call Key (`GCK`) used for this call.
  412. bytes gck = 2;
  413. // The base URL of the SFU, used to join or peek the call.
  414. string sfu_base_url = 3;
  415. }
  416. // React to a message.
  417. //
  418. // **Properties (1:1)**:
  419. // - Kind: 1:1
  420. // - Flags:
  421. // - `0x01`: Send push notification.
  422. // - User profile distribution: Yes
  423. // - Exempt from blocking: No
  424. // - Implicit _direct_ contact creation: No
  425. // - Protect against replay: Yes
  426. // - Reflect:
  427. // - Incoming: Yes
  428. // - Outgoing: Yes
  429. // - _Sent_ update: No
  430. // - Delivery receipts: No
  431. // - Reactions: No, that would be silly!
  432. // - When rejected: N/A (ignored)
  433. // - Edit applies to: N/A (can withdraw and apply with another `Reaction`)
  434. // - Deletable by: N/A (can withdraw with another `Reaction`)
  435. // - Include in history: Yes
  436. // - Send to Threema Gateway ID group creator: N/A
  437. //
  438. // **Properties (Group)**:
  439. // - Kind: 1:1
  440. // - Flags:
  441. // - `0x01`: Send push notification.
  442. // - User profile distribution: Yes
  443. // - Exempt from blocking: No
  444. // - Implicit _direct_ contact creation: No
  445. // - Protect against replay: Yes
  446. // - Reflect:
  447. // - Incoming: Yes
  448. // - Outgoing: Yes
  449. // - _Sent_ update: No
  450. // - Delivery receipts: N/A
  451. // - Reactions: No, that would be silly!
  452. // - When rejected: N/A (ignored)
  453. // - Edit applies to: N/A (can withdraw and apply with another `Reaction`)
  454. // - Deletable by: N/A (can withdraw with another `Reaction`)
  455. // - Include in history: Yes
  456. // - Send to Threema Gateway ID group creator: If capture is enabled
  457. //
  458. // When the user submits a reaction in a 1:1 conversation:
  459. //
  460. // 1. Let `reaction` be the reaction to be applied to or withdrawn from a
  461. // referred message which must contain a single fully-qualified [emoji
  462. // codepoint sequence that is part of the currently supported Unicode
  463. // standard][emoji-test.txt].
  464. // 2. Run the _Legacy Reaction Mapping Steps_ with `reaction` and let
  465. // `legacy-reaction` be the result.
  466. // 3. If `legacy-reaction` is not defined and the sender or the receiver does
  467. // not have `REACTION_SUPPORT`, log a warning and abort these steps.¹
  468. // 4. Let `reacted-at` be the current timestamp.
  469. // 5. If both sender and receiver have `REACTION_SUPPORT`, run the _1:1 Messages
  470. // Submit Steps_ with `messages` set from the following properties:
  471. // - `created-at` set to `reacted-at`,
  472. // - to construct a `Reaction` message from `reaction`.
  473. // 6. If the sender or the receiver does not have `REACTION_SUPPORT`, run the
  474. // _1:1 Messages Submit Steps_ with `messages` set from the following
  475. // properties:
  476. // - `created-at` set to `reacted-at`,
  477. // - to construct the `legacy-reaction`.
  478. // 7. Apply `reaction` (i.e. apply or withdraw) to the referred message with the
  479. // `reacted-at` timestamp.
  480. //
  481. // When the user submits a reaction in a group conversation:
  482. //
  483. // 1. Let `reaction` be the reaction to be applied to or withdrawn from a
  484. // referred message which must contain a single fully-qualified [emoji
  485. // codepoint sequence that is part of the currently supported Unicode
  486. // standard][emoji-test.txt].
  487. // 2. Run the _Legacy Reaction Mapping Steps_ with `reaction` and let
  488. // `legacy-reaction` be the result.
  489. // 3. If `legacy-reaction` is not defined:
  490. // 1. If the sender does not have `REACTION_SUPPORT`, log a warning and abort
  491. // these steps.²
  492. // 2. If all of the group members do not have `REACTION_SUPPORT`, log a
  493. // warning and and abort these steps.²
  494. // 3. If any of the group members do not have `REACTION_SUPPORT`, notify the
  495. // user that the affected contacts will not receive the reaction.
  496. // 4. Let `reacted-at` be the current timestamp.
  497. // 5. Run the _Group Messages Submit Steps_ with `messages` set from the
  498. // following properties:
  499. // - `created-at` set to `reacted-at`,
  500. // - to construct a _canonical_ `Reaction` message from `reaction`,
  501. // - to construct a _specific_ message in the following way:
  502. // 1. Let `receiver` be the specific receiver.
  503. // 2. If the `receiver` does not have `REACTION_SUPPORT` and
  504. // `legacy-reaction` is defined, return the `legacy-reaction` (wrapped
  505. // by [`group-member-container`](ref:e2e.group-member-container)).
  506. // 3. Construct and return the _canonical_ `Reaction` message from
  507. // `reaction` (wrapped by
  508. // [`group-member-container`](ref:e2e.group-member-container)).³
  509. // 6. Apply `reaction` (i.e. apply or withdraw) to the referred message with the
  510. // `reacted-at` timestamp.
  511. //
  512. // The following steps are defined as the _Legacy Reaction Mapping Steps_:
  513. //
  514. // 1. If `action` is of variant `apply`:
  515. // 1. If `action.apply` equals one of the following codepoint sequences,
  516. // return a `e2e.delivery-receipt` of type _acknowledge_ (0x03):
  517. // - `1F44D` (👍)
  518. // - `1F44D 1F3FB` (👍🏻)
  519. // - `1F44D 1F3FC` (👍🏼)
  520. // - `1F44D 1F3FD` (👍🏽)
  521. // - `1F44D 1F3FE` (👍🏾)
  522. // - `1F44D 1F3FF` (👍🏿)
  523. // 2. If `action.apply` equals one of the following codepoint sequences,
  524. // return a `e2e.delivery-receipt` of type _decline_ (0x04):
  525. // - `1F44E` (👎)
  526. // - `1F44E 1F3FB` (👎🏻)
  527. // - `1F44E 1F3FC` (👎🏼)
  528. // - `1F44E 1F3FD` (👎🏽)
  529. // - `1F44E 1F3FE` (👎🏾)
  530. // - `1F44E 1F3FF` (👎🏿)
  531. // 2. Return no message.
  532. //
  533. // When reflected from another device as an incoming or outgoing 1:1 message:
  534. //
  535. // 1. Run the _Common Reaction Receive Steps_.
  536. //
  537. // When receiving this message:
  538. //
  539. // 1. Run the _Common Reaction Receive Steps_.
  540. //
  541. // When receiving this message (wrapped by
  542. // [`group-member-container`](ref:e2e.group-member-container)):
  543. //
  544. // 1. Run the [_Common Group Receive Steps_](ref:e2e#receiving). If the reaction
  545. // message has been discarded, abort these steps.
  546. // 1. Run the _Common Reaction Receive Steps_.
  547. //
  548. // The following steps are defined as the _Common Reaction Receive Steps_:
  549. //
  550. // 1. Lookup the referred message with `message_id` within the associated
  551. // conversation and let `referred-message` be the result.
  552. // 2. If `referred-message` is not defined, discard the message and abort these
  553. // steps.
  554. // 3. If `referred-message` is not reactable (see the associated _Reactions_
  555. // property), discard the message and abort these steps.
  556. // 4. If `action` is of variant `apply`:
  557. // 1. If `apply` contains more than 64 bytes, discard the message and abort
  558. // these steps.
  559. // 2. Decode `apply` to a UTF-8 string. If the string is empty, discard the
  560. // message and abort these steps.
  561. // 3. Apply (or re-apply) the resulting emoji from the sender to
  562. // `referred-message` with the message's (the `Reaction`'s) `created-at`
  563. // timestamp used for the time of reaction.⁴⁵
  564. // 5. If `action` is of variant `withdraw`:
  565. // 1. If `withdraw` contains more than 64 bytes, discard the message and
  566. // abort these steps.
  567. // 2. Decode `withdraw` to a UTF-8 string. If the string is empty, discard
  568. // the message and abort these steps.
  569. // 3. Remove the resulting emoji reaction from the sender for `message`.⁴⁵
  570. //
  571. // ¹: The UI should not allow to create non-legacy reactions in 1:1
  572. // conversations with a sender or receiver that does not have
  573. // `REACTION_SUPPORT`.
  574. //
  575. // ²: The UI should not allow to create non-legacy reactions in group
  576. // conversations with a sender that does not have `REACTION_SUPPORT` or when all
  577. // other group members don't have `REACTION_SUPPORT`.
  578. //
  579. // ³: In case the reaction could not be mapped to a legacy reaction, this
  580. // results in a `Reaction` message being sent to group members that currently do
  581. // not support reactions. This is intentional.
  582. //
  583. // ⁴: Note that the _apply_ mechanism is additive, meaning multiple reactions
  584. // from the same sender are allowed on a single message. This is why the
  585. // _withdraw_ mechanism is needed which removes a specific reaction. On the
  586. // other hand, a deprecated `e2e.delivery-receipt` will replace all existing
  587. // reactions of the sender at once (including these new-style reactions).
  588. //
  589. // ⁵: The UI should display a placeholder (�) for unknown emojis, meaining those
  590. // which are not a single fully-qualified [emoji codepoint sequence that is part
  591. // of the currently supported Unicode standard][emoji-test.txt]. But the
  592. // individual code sequences still have individual display buckets.
  593. //
  594. // [emoji-test.txt]: https://www.unicode.org/Public/emoji/latest/emoji-test.txt
  595. message Reaction {
  596. // Unique ID of the referred message.
  597. fixed64 message_id = 1;
  598. // A single emoji reaction to be applied or withdrawn.
  599. oneof action {
  600. // Apply a new emoji reaction.
  601. bytes apply = 2;
  602. // Withdraw a specific emoji reaction.
  603. bytes withdraw = 3;
  604. }
  605. }
  606. // Request joining a group.
  607. //
  608. // This message is sent to the administrator of a group. The required
  609. // information is provided by a `GroupInvite` URL payload.
  610. //
  611. // **Properties**:
  612. // - Kind: 1:1
  613. // - Flags:
  614. // - `0x01`: Send push notification.
  615. // - User profile distribution: Yes
  616. // - Exempt from blocking: Yes
  617. // - Implicit _direct_ contact creation: Yes
  618. // - Protect against replay: Yes
  619. // - Reflect:
  620. // - Incoming: Yes
  621. // - Outgoing: Yes
  622. // - _Sent_ update: No
  623. // - Delivery receipts: No
  624. // - Reactions: No
  625. // - When rejected: N/A (ignored)
  626. // - Edit applies to: N/A
  627. // - Deletable by: User only
  628. // - Include in history: No
  629. // - Send to Threema Gateway ID group creator: N/A
  630. //
  631. // When receiving this message:
  632. //
  633. // 1. Look up the corresponding group invitation by the token.
  634. // 2. If the group invitation could not be found, discard the message and abort
  635. // these steps.
  636. // 3. If the sender is already part of the group, send an accept response and
  637. // then respond as if the sender had sent a `group-sync-request` (i.e. send a
  638. // `group-setup`, `group-name`, etc.). Finally, abort these steps.
  639. // 4. If the group name does not match the name in the originally sent group
  640. // invitation, discard the message and abort these steps.
  641. // 5. If the group invitation has expired, send the respective response and
  642. // abort these steps.
  643. // 6. If the group invitation requires the admin to accept the request, show
  644. // this information in the user interface and pause these steps until the
  645. // user manually confirmed of rejected the request. Note that the date of the
  646. // decision is allowed to extend beyond the expiration date of the group
  647. // invitation. Continue with the following sub-steps once the user made a
  648. // decision on the request:
  649. // 1. If the user manually rejected the request, send the respective
  650. // response and abort these steps.
  651. // 7. If the group is full, send the respective response and abort these steps.
  652. // 8. Send an accept response.
  653. // 9. Add the sender of the group invitation request to the group and follow the
  654. // group protocol from there.
  655. message GroupJoinRequest {
  656. // The group invite token, 16 bytes
  657. bytes token = 1;
  658. // The group name from the group invite URL
  659. string group_name = 2;
  660. // A message for the group administrator, e.g. for identification purposes
  661. //
  662. // The message helps the administrator to decide whether or not to accept a
  663. // join request.
  664. //
  665. // Should be requested by the user interface for invitations that require
  666. // manual confirmation by the administrator. Should not be requested in case
  667. // the invitation will be automatically accepted.
  668. string message = 3;
  669. }
  670. // Response sent by the admin of a group towards a sender of a valid group join
  671. // request.
  672. //
  673. // **Properties**:
  674. // - Kind: 1:1
  675. // - Flags: None
  676. // - User profile distribution: Yes
  677. // - Exempt from blocking: Yes
  678. // - Implicit _direct_ contact creation: Yes
  679. // - Protect against replay: Yes
  680. // - Reflect:
  681. // - Incoming: Yes
  682. // - Outgoing: Yes
  683. // - _Sent_ update: No
  684. // - Delivery receipts: No
  685. // - Reactions: No
  686. // - When rejected: N/A (ignored)
  687. // - Edit applies to: N/A
  688. // - Deletable by: N/A
  689. // - Include in history: Yes
  690. // - Send to Threema Gateway ID group creator: N/A
  691. //
  692. // When receiving this message:
  693. //
  694. // 1. Look up the corresponding group join request by the token and the
  695. // sender's Threema ID as the administrator's Threema ID.
  696. // 2. If the group join request could not be found, discard the message and
  697. // abort these steps.
  698. // 3. Mark the group join request as accepted or (automatically) rejected by
  699. // the given response type.
  700. // 4. If the group join request has been accepted, remember the group id in
  701. // order to be able to map an incoming `group-setup` to the group.
  702. message GroupJoinResponse {
  703. // The group invite token, 16 bytes
  704. bytes token = 1;
  705. // Response of the admin
  706. message Response {
  707. // Accept a group invite request
  708. message Accept {
  709. // Group ID (little-endian) as chosen by the group creator
  710. //
  711. // Note: Combined with the Threema ID of the administrator, this forms the
  712. // `GroupIdentity`.
  713. fixed64 group_id = 1;
  714. }
  715. oneof response {
  716. // Accept a group invite request
  717. Accept accept = 1;
  718. // Token of a group invitation expired
  719. common.Unit expired = 2;
  720. // Group invitation cannot be accepted due to the group being full
  721. common.Unit group_full = 3;
  722. // The administrator explicitly rejects the invitation request
  723. common.Unit reject = 4;
  724. }
  725. }
  726. Response response = 2;
  727. }