md-d2m.proto 9.7 KB

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