libQuotient
A Qt library for building matrix clients
keys.h
Go to the documentation of this file.
1 // THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
2 
3 #pragma once
4 
5 #include <Quotient/csapi/definitions/cross_signing_key.h>
6 #include <Quotient/csapi/definitions/device_keys.h>
7 
8 #include <Quotient/e2ee/e2ee_common.h>
9 
10 #include <Quotient/jobs/basejob.h>
11 
12 namespace Quotient {
13 
14 //! \brief Upload end-to-end encryption keys.
15 //!
16 //! Publishes end-to-end encryption keys for the device.
17 class QUOTIENT_API UploadKeysJob : public BaseJob {
18 public:
19  //! \param deviceKeys
20  //! Identity keys for the device. May be absent if no new
21  //! identity keys are required.
22  //!
23  //! \param oneTimeKeys
24  //! One-time public keys for "pre-key" messages. The names of
25  //! the properties should be in the format
26  //! `<algorithm>:<key_id>`. The format of the key is determined
27  //! by the [key algorithm](/client-server-api/#key-algorithms).
28  //!
29  //! May be absent if no new one-time keys are required.
30  //!
31  //! \param fallbackKeys
32  //! The public key which should be used if the device's one-time keys
33  //! are exhausted. The fallback key is not deleted once used, but should
34  //! be replaced when additional one-time keys are being uploaded. The
35  //! server will notify the client of the fallback key being used through
36  //! `/sync`.
37  //!
38  //! There can only be at most one key per algorithm uploaded, and the server
39  //! will only persist one key per algorithm.
40  //!
41  //! When uploading a signed key, an additional `fallback: true` key should
42  //! be included to denote that the key is a fallback key.
43  //!
44  //! May be absent if a new fallback key is not required.
45  explicit UploadKeysJob(const std::optional<DeviceKeys>& deviceKeys = std::nullopt,
46  const OneTimeKeys& oneTimeKeys = {},
47  const OneTimeKeys& fallbackKeys = {});
48 
49  // Result properties
50 
51  //! For each key algorithm, the number of unclaimed one-time keys
52  //! of that type currently held on the server for this device.
53  //! If an algorithm is not listed, the count for that algorithm
54  //! is to be assumed zero.
55  QHash<QString, int> oneTimeKeyCounts() const
56  {
57  return loadFromJson<QHash<QString, int>>("one_time_key_counts"_L1);
58  }
59 };
60 
61 inline auto collectResponse(const UploadKeysJob* job) { return job->oneTimeKeyCounts(); }
62 
63 //! \brief Download device identity keys.
64 //!
65 //! Returns the current devices and identity keys for the given users.
66 class QUOTIENT_API QueryKeysJob : public BaseJob {
67 public:
68  // Inner data structures
69 
70  //! Additional data added to the device key information
71  //! by intermediate servers, and not covered by the
72  //! signatures.
73  struct QUOTIENT_API UnsignedDeviceInfo {
74  //! The display name which the user set on the device.
75  QString deviceDisplayName{};
76  };
77 
78  struct QUOTIENT_API DeviceInformation : DeviceKeys {
79  //! Additional data added to the device key information
80  //! by intermediate servers, and not covered by the
81  //! signatures.
82  std::optional<UnsignedDeviceInfo> unsignedData{};
83  };
84 
85  // Construction/destruction
86 
87  //! \param deviceKeys
88  //! The keys to be downloaded. A map from user ID, to a list of
89  //! device IDs, or to an empty list to indicate all devices for the
90  //! corresponding user.
91  //!
92  //! \param timeout
93  //! The time (in milliseconds) to wait when downloading keys from
94  //! remote servers. 10 seconds is the recommended default.
95  explicit QueryKeysJob(const QHash<UserId, QStringList>& deviceKeys,
96  std::optional<int> timeout = std::nullopt);
97 
98  // Result properties
99 
100  //! If any remote homeservers could not be reached, they are
101  //! recorded here. The names of the properties are the names of
102  //! the unreachable servers.
103  //!
104  //! If the homeserver could be reached, but the user or device
105  //! was unknown, no failure is recorded. Instead, the corresponding
106  //! user or device is missing from the `device_keys` result.
107  QHash<QString, QJsonObject> failures() const
108  {
109  return loadFromJson<QHash<QString, QJsonObject>>("failures"_L1);
110  }
111 
112  //! Information on the queried devices. A map from user ID, to a
113  //! map from device ID to device information. For each device,
114  //! the information returned will be the same as uploaded via
115  //! `/keys/upload`, with the addition of an `unsigned`
116  //! property.
117  QHash<UserId, QHash<QString, DeviceInformation>> deviceKeys() const
118  {
119  return loadFromJson<QHash<UserId, QHash<QString, DeviceInformation>>>("device_keys"_L1);
120  }
121 
122  //! Information on the master cross-signing keys of the queried users.
123  //! A map from user ID, to master key information. For each key, the
124  //! information returned will be the same as uploaded via
125  //! `/keys/device_signing/upload`, along with the signatures
126  //! uploaded via `/keys/signatures/upload` that the requesting user
127  //! is allowed to see.
128  QHash<UserId, CrossSigningKey> masterKeys() const
129  {
130  return loadFromJson<QHash<UserId, CrossSigningKey>>("master_keys"_L1);
131  }
132 
133  //! Information on the self-signing keys of the queried users. A map
134  //! from user ID, to self-signing key information. For each key, the
135  //! information returned will be the same as uploaded via
136  //! `/keys/device_signing/upload`.
137  QHash<UserId, CrossSigningKey> selfSigningKeys() const
138  {
139  return loadFromJson<QHash<UserId, CrossSigningKey>>("self_signing_keys"_L1);
140  }
141 
142  //! Information on the user-signing key of the user making the
143  //! request, if they queried their own device information. A map
144  //! from user ID, to user-signing key information. The
145  //! information returned will be the same as uploaded via
146  //! `/keys/device_signing/upload`.
147  QHash<UserId, CrossSigningKey> userSigningKeys() const
148  {
149  return loadFromJson<QHash<UserId, CrossSigningKey>>("user_signing_keys"_L1);
150  }
151 
152  struct Response {
153  //! If any remote homeservers could not be reached, they are
154  //! recorded here. The names of the properties are the names of
155  //! the unreachable servers.
156  //!
157  //! If the homeserver could be reached, but the user or device
158  //! was unknown, no failure is recorded. Instead, the corresponding
159  //! user or device is missing from the `device_keys` result.
160  QHash<QString, QJsonObject> failures{};
161 
162  //! Information on the queried devices. A map from user ID, to a
163  //! map from device ID to device information. For each device,
164  //! the information returned will be the same as uploaded via
165  //! `/keys/upload`, with the addition of an `unsigned`
166  //! property.
167  QHash<UserId, QHash<QString, DeviceInformation>> deviceKeys{};
168 
169  //! Information on the master cross-signing keys of the queried users.
170  //! A map from user ID, to master key information. For each key, the
171  //! information returned will be the same as uploaded via
172  //! `/keys/device_signing/upload`, along with the signatures
173  //! uploaded via `/keys/signatures/upload` that the requesting user
174  //! is allowed to see.
175  QHash<UserId, CrossSigningKey> masterKeys{};
176 
177  //! Information on the self-signing keys of the queried users. A map
178  //! from user ID, to self-signing key information. For each key, the
179  //! information returned will be the same as uploaded via
180  //! `/keys/device_signing/upload`.
181  QHash<UserId, CrossSigningKey> selfSigningKeys{};
182 
183  //! Information on the user-signing key of the user making the
184  //! request, if they queried their own device information. A map
185  //! from user ID, to user-signing key information. The
186  //! information returned will be the same as uploaded via
187  //! `/keys/device_signing/upload`.
188  QHash<UserId, CrossSigningKey> userSigningKeys{};
189  };
190 };
191 
192 template <std::derived_from<QueryKeysJob> JobT>
193 constexpr inline auto doCollectResponse<JobT> = [](JobT* j) -> QueryKeysJob::Response {
194  return { j->failures(), j->deviceKeys(), j->masterKeys(), j->selfSigningKeys(),
195  j->userSigningKeys() };
196 };
197 
198 template <>
199 struct QUOTIENT_API JsonObjectConverter<QueryKeysJob::UnsignedDeviceInfo> {
200  static void fillFrom(const QJsonObject& jo, QueryKeysJob::UnsignedDeviceInfo& result)
201  {
202  fillFromJson(jo.value("device_display_name"_L1), result.deviceDisplayName);
203  }
204 };
205 
206 template <>
207 struct QUOTIENT_API JsonObjectConverter<QueryKeysJob::DeviceInformation> {
208  static void fillFrom(const QJsonObject& jo, QueryKeysJob::DeviceInformation& result)
209  {
210  fillFromJson<DeviceKeys>(jo, result);
211  fillFromJson(jo.value("unsigned"_L1), result.unsignedData);
212  }
213 };
214 
215 //! \brief Claim one-time encryption keys.
216 //!
217 //! Claims one-time keys for use in pre-key messages.
218 class QUOTIENT_API ClaimKeysJob : public BaseJob {
219 public:
220  //! \param oneTimeKeys
221  //! The keys to be claimed. A map from user ID, to a map from
222  //! device ID to algorithm name.
223  //!
224  //! \param timeout
225  //! The time (in milliseconds) to wait when downloading keys from
226  //! remote servers. 10 seconds is the recommended default.
227  explicit ClaimKeysJob(const QHash<UserId, QHash<QString, QString>>& oneTimeKeys,
228  std::optional<int> timeout = std::nullopt);
229 
230  // Result properties
231 
232  //! If any remote homeservers could not be reached, they are
233  //! recorded here. The names of the properties are the names of
234  //! the unreachable servers.
235  //!
236  //! If the homeserver could be reached, but the user or device
237  //! was unknown, no failure is recorded. Instead, the corresponding
238  //! user or device is missing from the `one_time_keys` result.
239  QHash<QString, QJsonObject> failures() const
240  {
241  return loadFromJson<QHash<QString, QJsonObject>>("failures"_L1);
242  }
243 
244  //! One-time keys for the queried devices. A map from user ID, to a
245  //! map from devices to a map from `<algorithm>:<key_id>` to the key object.
246  //!
247  //! See the [key algorithms](/client-server-api/#key-algorithms) section for information
248  //! on the Key Object format.
249  //!
250  //! If necessary, the claimed key might be a fallback key. Fallback
251  //! keys are re-used by the server until replaced by the device.
252  QHash<UserId, QHash<QString, OneTimeKeys>> oneTimeKeys() const
253  {
254  return loadFromJson<QHash<UserId, QHash<QString, OneTimeKeys>>>("one_time_keys"_L1);
255  }
256 
257  struct Response {
258  //! If any remote homeservers could not be reached, they are
259  //! recorded here. The names of the properties are the names of
260  //! the unreachable servers.
261  //!
262  //! If the homeserver could be reached, but the user or device
263  //! was unknown, no failure is recorded. Instead, the corresponding
264  //! user or device is missing from the `one_time_keys` result.
265  QHash<QString, QJsonObject> failures{};
266 
267  //! One-time keys for the queried devices. A map from user ID, to a
268  //! map from devices to a map from `<algorithm>:<key_id>` to the key object.
269  //!
270  //! See the [key algorithms](/client-server-api/#key-algorithms) section for information
271  //! on the Key Object format.
272  //!
273  //! If necessary, the claimed key might be a fallback key. Fallback
274  //! keys are re-used by the server until replaced by the device.
275  QHash<UserId, QHash<QString, OneTimeKeys>> oneTimeKeys{};
276  };
277 };
278 
279 template <std::derived_from<ClaimKeysJob> JobT>
280 constexpr inline auto doCollectResponse<JobT> =
281  [](JobT* j) -> ClaimKeysJob::Response { return { j->failures(), j->oneTimeKeys() }; };
282 
283 //! \brief Query users with recent device key updates.
284 //!
285 //! Gets a list of users who have updated their device identity keys since a
286 //! previous sync token.
287 //!
288 //! The server should include in the results any users who:
289 //!
290 //! * currently share a room with the calling user (ie, both users have
291 //! membership state `join`); *and*
292 //! * added new device identity keys or removed an existing device with
293 //! identity keys, between `from` and `to`.
294 class QUOTIENT_API GetKeysChangesJob : public BaseJob {
295 public:
296  //! \param from
297  //! The desired start point of the list. Should be the `next_batch` field
298  //! from a response to an earlier call to
299  //! [`/sync`](/client-server-api/#get_matrixclientv3sync). Users who have not uploaded new
300  //! device identity keys since this point, nor deleted existing devices with identity keys
301  //! since then, will be excluded from the results.
302  //!
303  //! \param to
304  //! The desired end point of the list. Should be the `next_batch`
305  //! field from a recent call to [`/sync`](/client-server-api/#get_matrixclientv3sync) -
306  //! typically the most recent such call. This may be used by the server as a hint to check its
307  //! caches are up to date.
308  explicit GetKeysChangesJob(const QString& from, const QString& to);
309 
310  //! \brief Construct a URL without creating a full-fledged job object
311  //!
312  //! This function can be used when a URL for GetKeysChangesJob
313  //! is necessary but the job itself isn't.
314  static QUrl makeRequestUrl(const HomeserverData& hsData, const QString& from, const QString& to);
315 
316  // Result properties
317 
318  //! The Matrix User IDs of all users who updated their device
319  //! identity keys.
320  QStringList changed() const { return loadFromJson<QStringList>("changed"_L1); }
321 
322  //! The Matrix User IDs of all users who may have left all
323  //! the end-to-end encrypted rooms they previously shared
324  //! with the user.
325  QStringList left() const { return loadFromJson<QStringList>("left"_L1); }
326 
327  struct Response {
328  //! The Matrix User IDs of all users who updated their device
329  //! identity keys.
330  QStringList changed{};
331 
332  //! The Matrix User IDs of all users who may have left all
333  //! the end-to-end encrypted rooms they previously shared
334  //! with the user.
335  QStringList left{};
336  };
337 };
338 
339 template <std::derived_from<GetKeysChangesJob> JobT>
340 constexpr inline auto doCollectResponse<JobT> =
341  [](JobT* j) -> GetKeysChangesJob::Response { return { j->changed(), j->left() }; };
342 
343 } // namespace Quotient