md-d2m.proto 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. // ## Device to Mediator Protocol (Supplementary)
  2. //
  3. // This is a supplementary section to the corresponding structbuf section
  4. // with complementary messages that use protobuf instead of structbuf. All
  5. // defined messages here follow the same logic.
  6. //
  7. // Note that all messages defined here, with the exception of `ClientUrlInfo`,
  8. // are wrapped by `payload.container`.
  9. syntax = "proto3";
  10. package d2m;
  11. option java_package = "ch.threema.protobuf.d2m";
  12. // D2M protocol versions.
  13. enum ProtocolVersion {
  14. // Initial D2M protocol version (alpha, may break).
  15. V0 = 0;
  16. }
  17. // Send along client information when connecting to the mediator server.
  18. //
  19. // This message is serialized, hex-encoded (lowercase) and then used as the
  20. // WebSocket path.
  21. //
  22. // Type: n/a
  23. // Direction: Client -> Server
  24. message ClientUrlInfo {
  25. reserved 2; // Deprecated numeric server group
  26. // 32 byte device group id (`DGPK.public`)
  27. bytes device_group_id = 1;
  28. // Server group, as assigned by the server when the Threema identity has been
  29. // created. Must consist of only digits or ASCII letters (`^[0-9a-zA-Z]+$`).
  30. string server_group = 3;
  31. }
  32. // Initial message from the server, containing an authentication challenge.
  33. //
  34. // Type: 0x10
  35. // Direction: Client <-- Server
  36. message ServerHello {
  37. // Highest protocol version (`ProtocolVersion`) the server supports.
  38. uint32 version = 1;
  39. // 32 byte ephemeral server key (`ESK.public`)
  40. bytes esk = 2;
  41. // 32 byte random challenge
  42. bytes challenge = 3;
  43. }
  44. // Policy determining the device slot's lifetime.
  45. enum DeviceSlotExpirationPolicy {
  46. // The device slot should be removed shortly after the device
  47. // disconnected. However, there should be a delay of several minutes to
  48. // ensure that the device can reconnect if it disconnected unintentionally.
  49. VOLATILE = 0;
  50. // The device slot should be kept as long as possible
  51. PERSISTENT = 1;
  52. }
  53. // Device registration state on the mediator server.
  54. enum DeviceSlotState {
  55. // A new device slot has been allocated for the device (i.e. the device's
  56. // id was not registered on the server).
  57. NEW = 0;
  58. // An existing device slot has been reused for the device (i.e. the
  59. // device's id is already registered on the server).
  60. EXISTING = 1;
  61. }
  62. // Initial message from the client, containing the authentication challenge
  63. // response and additional login information.
  64. //
  65. // Type: 0x11
  66. // Direction: Client --> Server
  67. message ClientHello {
  68. // Protocol version (`ProtocolVersion`) which the client has selected.
  69. uint32 version = 1;
  70. // Challenge response (72 bytes) for authentication.
  71. //
  72. // The response is created by encrypting the server's challenge in the
  73. // following way:
  74. //
  75. // ```text
  76. // XSalsa20-Poly1305(
  77. // key=X25519HSalsa20(DGPK.secret, ESK.public),
  78. // nonce=<random>,
  79. // )
  80. // ```
  81. //
  82. // The nonce is then prefixed to the encrypted challenge.
  83. bytes response = 2;
  84. // Unique device id
  85. fixed64 device_id = 3;
  86. // Policy to be applied in case the device id is not registered on the server
  87. // and all device slots have been exhausted.
  88. enum DeviceSlotsExhaustedPolicy {
  89. // Terminate the connection
  90. REJECT = 0;
  91. // Drop the least recently used device
  92. DROP_LEAST_RECENT = 1;
  93. }
  94. DeviceSlotsExhaustedPolicy device_slots_exhausted_policy = 4;
  95. // Policy determining the device slot's lifetime
  96. DeviceSlotExpirationPolicy device_slot_expiration_policy = 5;
  97. // The expected device slot state on the server.
  98. //
  99. // If the expected device slot state does not match the actual device slot
  100. // state, the device will be dropped by the mediator server with the close
  101. // code `4115` before being registered.
  102. DeviceSlotState expected_device_slot_state = 7;
  103. // Device info (`d2d.DeviceInfo`), encrypted by `DGDIK.secret` and prefixed
  104. // with a random nonce.
  105. bytes encrypted_device_info = 6;
  106. }
  107. // Parts of the server's configuration and the device slot state.
  108. //
  109. // Type: 0x12
  110. // Direction: Client <-- Server
  111. message ServerInfo {
  112. // Current Unix-ish timestamp in milliseconds of the server.
  113. //
  114. // If the client's current timestamp deviates by more than 20 minutes, the
  115. // client should disconnect and prompt the user to synchronise its clock.
  116. // The user should also have an option to _connect anyway_ which should be
  117. // cached for a reasonable amount of time.
  118. uint64 current_time = 4;
  119. // Maximum number of device slots
  120. uint32 max_device_slots = 1;
  121. // Informs the device about its device slot state on the server
  122. DeviceSlotState device_slot_state = 2;
  123. // Device data shared among devices (`SharedDeviceData`), encrypted by
  124. // `DGSDDK.secret` and prefixed with a random nonce.
  125. bytes encrypted_shared_device_data = 3;
  126. // Amount of messages in the reflection queue that will now be sent to the
  127. // device. If the client is up-to-date, the value will be 0.
  128. //
  129. // Note: The amount of messages in the reflection queue may increase at any
  130. // time, so there is no guarantee that `ReflectionQueueDry` will be received
  131. // after having received `reflection_queue_length` reflected messages.
  132. uint32 reflection_queue_length = 5;
  133. }
  134. // The device's reflection queue on the server has been fully transmitted to
  135. // the device.
  136. //
  137. // Note: This does not mean that reflected messages have already been
  138. // acknowledged by the device!
  139. //
  140. // Type: 0x20
  141. // Direction: Client <-- Server
  142. message ReflectionQueueDry {}
  143. // The device's role has been promoted to leader, indicating that the device
  144. // should now request to receive and reflect messages from the chat server.
  145. //
  146. // Type: 0x21
  147. // Direction: Client <-- Server
  148. message RolePromotedToLeader {}
  149. // Request device information of all devices.
  150. //
  151. // Type: 0x30
  152. // Direction: Client --> Server
  153. message GetDevicesInfo {}
  154. // Device information of all devices.
  155. //
  156. // Type: 0x31
  157. // Direction: Client <-- Server
  158. message DevicesInfo {
  159. // Device id to (augmented) device info map of all devices.
  160. message AugmentedDeviceInfo {
  161. // Device info (`d2d.DeviceInfo`), encrypted by `DGDIK.secret` and prefixed
  162. // with a random nonce.
  163. bytes encrypted_device_info = 1;
  164. // Connection state
  165. oneof connection_state {
  166. // Unix-ish timestamp in milliseconds containing the most recent login
  167. // time of the device. Only set if device is currently connected.
  168. uint64 connected_since = 2;
  169. // Unix-ish timestamp in milliseconds containing the most recent
  170. // disconnect time of the device. Only set if device is not connected.
  171. uint64 last_disconnect_at = 4;
  172. }
  173. // Expiration policy of the device.
  174. DeviceSlotExpirationPolicy device_slot_expiration_policy = 3;
  175. }
  176. map<fixed64, AugmentedDeviceInfo> augmented_device_info = 1;
  177. }
  178. // Request to drop a device and free its device slot.
  179. //
  180. // Type: 0x32
  181. // Direction: Client --> Server
  182. message DropDevice {
  183. // Unique device id
  184. fixed64 device_id = 1;
  185. }
  186. // Acknowledges that a device has been dropped and the device slot has been
  187. // free'd.
  188. //
  189. // Type: 0x33
  190. // Direction: Client <-- Server
  191. message DropDeviceAck {
  192. // Unique device id
  193. fixed64 device_id = 1;
  194. }
  195. // Set the shared device data which is being sent to each device during login.
  196. //
  197. // Type: 0x34
  198. // Direction: Client --> Server
  199. message SetSharedDeviceData {
  200. // Device data shared among devices (`d2d.SharedDeviceData`), encrypted by
  201. // `DGSDDK.secret` and prefixed with a random nonce.
  202. bytes encrypted_shared_device_data = 1;
  203. }
  204. // Acquires a device group lock for an atomic operation shared across the
  205. // device group.
  206. //
  207. // Reflection messages from the device to the mediator server will only be
  208. // reflected once the transaction is committed.
  209. //
  210. // Type: 0x40
  211. // Direction: Client --> Server
  212. message BeginTransaction {
  213. // The transaction scope (`d2d.TransactionScope`), encrypted by
  214. // `DGTSK.secret` and prefixed with a random nonce.
  215. bytes encrypted_scope = 1;
  216. // Time-to-live in seconds for this transaction. Once the TTL is reached, the
  217. // mediator server will abort the transaction and disconnect the client. When
  218. // set to `0`, the server's maximum transaction TTL will be used.
  219. uint32 ttl = 2;
  220. }
  221. // Acknowledges that the device group lock has been acquired and that the
  222. // transaction has been started.
  223. //
  224. // Type: 0x41
  225. // Direction: Client <-- Server
  226. message BeginTransactionAck {}
  227. // Commits a transaction, releases a device group lock.
  228. //
  229. // Type: 0x42
  230. // Direction: Client --> Server
  231. message CommitTransaction {}
  232. // Acknowledges that the transaction has been committed and that the device
  233. // group lock has been released.
  234. //
  235. // Type: 0x43
  236. // Direction: Client <-- Server
  237. message CommitTransactionAck {}
  238. // A `BeginTransaction` request is rejected because another transaction is
  239. // already in process.
  240. //
  241. // Type: 0x44
  242. // Direction: Client <-- Server
  243. message TransactionRejected {
  244. // The device that currently holds the lock
  245. fixed64 device_id = 1;
  246. // The encrypted transaction scope (`d2d.TransactionScope`) associated with
  247. // the currently locked transaction, encrypted by `DGTSK.secret` and prefixed
  248. // with a random nonce.
  249. bytes encrypted_scope = 2;
  250. }
  251. // When a transaction ends (either because it was committed or because the
  252. // device disconnected), this message is sent to all connected devices except
  253. // for the device that committed the transaction.
  254. //
  255. // This can be used by the other devices as a "retry signal" if a previous
  256. // "BeginTransaction" attempt was unsuccessful.
  257. //
  258. // Type: 0x45
  259. // Direction: Client <-- Server
  260. message TransactionEnded {
  261. // The device that held the lock up until now
  262. fixed64 device_id = 1;
  263. // The encrypted transaction scope (`d2d.TransactionScope`) associated with
  264. // the transaction that just ended, encrypted by `DGTSK.secret` and prefixed
  265. // with a random nonce.
  266. bytes encrypted_scope = 2;
  267. }