diff options
Diffstat (limited to 'lib/csapi/keys.h')
-rw-r--r-- | lib/csapi/keys.h | 473 |
1 files changed, 275 insertions, 198 deletions
diff --git a/lib/csapi/keys.h b/lib/csapi/keys.h index e59b1dae..b28de305 100644 --- a/lib/csapi/keys.h +++ b/lib/csapi/keys.h @@ -4,216 +4,293 @@ #pragma once +#include "csapi/definitions/cross_signing_key.h" +#include "csapi/definitions/device_keys.h" + +#include "e2ee/e2ee.h" + #include "jobs/basejob.h" -#include "csapi/definitions/device_keys.h" -#include <QtCore/QHash> -#include "converters.h" -#include <QtCore/QVariant> -#include <QtCore/QJsonObject> +namespace Quotient { -namespace QMatrixClient -{ - // Operations +/*! \brief Upload end-to-end encryption keys. + * + * Publishes end-to-end encryption keys for the device. + */ +class QUOTIENT_API UploadKeysJob : public BaseJob { +public: + /*! \brief Upload end-to-end encryption keys. + * + * \param deviceKeys + * Identity keys for the device. May be absent if no new + * identity keys are required. + * + * \param oneTimeKeys + * One-time public keys for "pre-key" messages. The names of + * the properties should be in the format + * `<algorithm>:<key_id>`. The format of the key is determined + * by the [key algorithm](/client-server-api/#key-algorithms). + * + * May be absent if no new one-time keys are required. + * + * \param fallbackKeys + * The public key which should be used if the device's one-time keys + * are exhausted. The fallback key is not deleted once used, but should + * be replaced when additional one-time keys are being uploaded. The + * server will notify the client of the fallback key being used through + * `/sync`. + * + * There can only be at most one key per algorithm uploaded, and the + * server will only persist one key per algorithm. + * + * When uploading a signed key, an additional `fallback: true` key should + * be included to denote that the key is a fallback key. + * + * May be absent if a new fallback key is not required. + */ + explicit UploadKeysJob(const Omittable<DeviceKeys>& deviceKeys = none, + const OneTimeKeys& oneTimeKeys = {}, + const OneTimeKeys& fallbackKeys = {}); - /// Upload end-to-end encryption keys. - /// - /// Publishes end-to-end encryption keys for the device. - class UploadKeysJob : public BaseJob + // Result properties + + /// For each key algorithm, the number of unclaimed one-time keys + /// of that type currently held on the server for this device. + /// If an algorithm is not listed, the count for that algorithm + /// is to be assumed zero. + QHash<QString, int> oneTimeKeyCounts() const { - public: - /*! Upload end-to-end encryption keys. - * \param deviceKeys - * Identity keys for the device. May be absent if no new - * identity keys are required. - * \param oneTimeKeys - * One-time public keys for "pre-key" messages. The names of - * the properties should be in the format - * ``<algorithm>:<key_id>``. The format of the key is determined - * by the key algorithm. - * - * May be absent if no new one-time keys are required. - */ - explicit UploadKeysJob(const Omittable<DeviceKeys>& deviceKeys = none, const QHash<QString, QVariant>& oneTimeKeys = {}); - ~UploadKeysJob() override; - - // Result properties - - /// For each key algorithm, the number of unclaimed one-time keys - /// of that type currently held on the server for this device. - const QHash<QString, int>& oneTimeKeyCounts() const; - - protected: - Status parseJson(const QJsonDocument& data) override; - - private: - class Private; - QScopedPointer<Private> d; + return loadFromJson<QHash<QString, int>>("one_time_key_counts"_ls); + } +}; + +/*! \brief Download device identity keys. + * + * Returns the current devices and identity keys for the given users. + */ +class QUOTIENT_API QueryKeysJob : public BaseJob { +public: + // Inner data structures + + /// Additional data added to the device key information + /// by intermediate servers, and not covered by the + /// signatures. + struct UnsignedDeviceInfo { + /// The display name which the user set on the device. + QString deviceDisplayName; }; - /// Download device identity keys. - /// /// Returns the current devices and identity keys for the given users. - class QueryKeysJob : public BaseJob - { - public: - // Inner data structures - - /// Additional data added to the device key information - /// by intermediate servers, and not covered by the - /// signatures. - struct UnsignedDeviceInfo - { - /// The display name which the user set on the device. - QString deviceDisplayName; - }; - - /// Returns the current devices and identity keys for the given users. - struct DeviceInformation : DeviceKeys - { - /// Additional data added to the device key information - /// by intermediate servers, and not covered by the - /// signatures. - Omittable<UnsignedDeviceInfo> unsignedData; - }; - - // Construction/destruction - - /*! Download device identity keys. - * \param deviceKeys - * The keys to be downloaded. A map from user ID, to a list of - * device IDs, or to an empty list to indicate all devices for the - * corresponding user. - * \param timeout - * The time (in milliseconds) to wait when downloading keys from - * remote servers. 10 seconds is the recommended default. - * \param token - * If the client is fetching keys as a result of a device update received - * in a sync request, this should be the 'since' token of that sync request, - * or any later sync token. This allows the server to ensure its response - * contains the keys advertised by the notification in that sync. - */ - explicit QueryKeysJob(const QHash<QString, QStringList>& deviceKeys, Omittable<int> timeout = none, const QString& token = {}); - ~QueryKeysJob() override; - - // Result properties - - /// If any remote homeservers could not be reached, they are - /// recorded here. The names of the properties are the names of - /// the unreachable servers. - /// - /// If the homeserver could be reached, but the user or device - /// was unknown, no failure is recorded. Instead, the corresponding - /// user or device is missing from the ``device_keys`` result. - const QHash<QString, QJsonObject>& failures() const; - /// Information on the queried devices. A map from user ID, to a - /// map from device ID to device information. For each device, - /// the information returned will be the same as uploaded via - /// ``/keys/upload``, with the addition of an ``unsigned`` - /// property. - const QHash<QString, QHash<QString, DeviceInformation>>& deviceKeys() const; - - protected: - Status parseJson(const QJsonDocument& data) override; - - private: - class Private; - QScopedPointer<Private> d; + struct DeviceInformation : DeviceKeys { + /// Additional data added to the device key information + /// by intermediate servers, and not covered by the + /// signatures. + Omittable<UnsignedDeviceInfo> unsignedData; }; - /// Claim one-time encryption keys. + // Construction/destruction + + /*! \brief Download device identity keys. + * + * \param deviceKeys + * The keys to be downloaded. A map from user ID, to a list of + * device IDs, or to an empty list to indicate all devices for the + * corresponding user. + * + * \param timeout + * The time (in milliseconds) to wait when downloading keys from + * remote servers. 10 seconds is the recommended default. + * + * \param token + * If the client is fetching keys as a result of a device update received + * in a sync request, this should be the 'since' token of that sync + * request, or any later sync token. This allows the server to ensure its + * response contains the keys advertised by the notification in that sync. + */ + explicit QueryKeysJob(const QHash<QString, QStringList>& deviceKeys, + Omittable<int> timeout = none, + const QString& token = {}); + + // Result properties + + /// If any remote homeservers could not be reached, they are + /// recorded here. The names of the properties are the names of + /// the unreachable servers. /// - /// Claims one-time keys for use in pre-key messages. - class ClaimKeysJob : public BaseJob + /// If the homeserver could be reached, but the user or device + /// was unknown, no failure is recorded. Instead, the corresponding + /// user or device is missing from the `device_keys` result. + QHash<QString, QJsonObject> failures() const { - public: - /*! Claim one-time encryption keys. - * \param oneTimeKeys - * The keys to be claimed. A map from user ID, to a map from - * device ID to algorithm name. - * \param timeout - * The time (in milliseconds) to wait when downloading keys from - * remote servers. 10 seconds is the recommended default. - */ - explicit ClaimKeysJob(const QHash<QString, QHash<QString, QString>>& oneTimeKeys, Omittable<int> timeout = none); - ~ClaimKeysJob() override; - - // Result properties - - /// If any remote homeservers could not be reached, they are - /// recorded here. The names of the properties are the names of - /// the unreachable servers. - /// - /// If the homeserver could be reached, but the user or device - /// was unknown, no failure is recorded. Instead, the corresponding - /// user or device is missing from the ``one_time_keys`` result. - const QHash<QString, QJsonObject>& failures() const; - /// One-time keys for the queried devices. A map from user ID, to a - /// map from devices to a map from ``<algorithm>:<key_id>`` to the key object. - const QHash<QString, QHash<QString, QVariant>>& oneTimeKeys() const; - - protected: - Status parseJson(const QJsonDocument& data) override; - - private: - class Private; - QScopedPointer<Private> d; - }; + return loadFromJson<QHash<QString, QJsonObject>>("failures"_ls); + } + + /// Information on the queried devices. A map from user ID, to a + /// map from device ID to device information. For each device, + /// the information returned will be the same as uploaded via + /// `/keys/upload`, with the addition of an `unsigned` + /// property. + QHash<QString, QHash<QString, DeviceInformation>> deviceKeys() const + { + return loadFromJson<QHash<QString, QHash<QString, DeviceInformation>>>( + "device_keys"_ls); + } + + /// Information on the master cross-signing keys of the queried users. + /// A map from user ID, to master key information. For each key, the + /// information returned will be the same as uploaded via + /// `/keys/device_signing/upload`, along with the signatures + /// uploaded via `/keys/signatures/upload` that the requesting user + /// is allowed to see. + QHash<QString, CrossSigningKey> masterKeys() const + { + return loadFromJson<QHash<QString, CrossSigningKey>>("master_keys"_ls); + } + + /// Information on the self-signing keys of the queried users. A map + /// from user ID, to self-signing key information. For each key, the + /// information returned will be the same as uploaded via + /// `/keys/device_signing/upload`. + QHash<QString, CrossSigningKey> selfSigningKeys() const + { + return loadFromJson<QHash<QString, CrossSigningKey>>( + "self_signing_keys"_ls); + } - /// Query users with recent device key updates. + /// Information on the user-signing key of the user making the + /// request, if they queried their own device information. A map + /// from user ID, to user-signing key information. The + /// information returned will be the same as uploaded via + /// `/keys/device_signing/upload`. + QHash<QString, CrossSigningKey> userSigningKeys() const + { + return loadFromJson<QHash<QString, CrossSigningKey>>( + "user_signing_keys"_ls); + } +}; + +template <> +struct JsonObjectConverter<QueryKeysJob::UnsignedDeviceInfo> { + static void fillFrom(const QJsonObject& jo, + QueryKeysJob::UnsignedDeviceInfo& result) + { + fromJson(jo.value("device_display_name"_ls), result.deviceDisplayName); + } +}; + +template <> +struct JsonObjectConverter<QueryKeysJob::DeviceInformation> { + static void fillFrom(const QJsonObject& jo, + QueryKeysJob::DeviceInformation& result) + { + fillFromJson<DeviceKeys>(jo, result); + fromJson(jo.value("unsigned"_ls), result.unsignedData); + } +}; + +/*! \brief Claim one-time encryption keys. + * + * Claims one-time keys for use in pre-key messages. + */ +class QUOTIENT_API ClaimKeysJob : public BaseJob { +public: + /*! \brief Claim one-time encryption keys. + * + * \param oneTimeKeys + * The keys to be claimed. A map from user ID, to a map from + * device ID to algorithm name. + * + * \param timeout + * The time (in milliseconds) to wait when downloading keys from + * remote servers. 10 seconds is the recommended default. + */ + explicit ClaimKeysJob( + const QHash<QString, QHash<QString, QString>>& oneTimeKeys, + Omittable<int> timeout = none); + + // Result properties + + /// If any remote homeservers could not be reached, they are + /// recorded here. The names of the properties are the names of + /// the unreachable servers. /// - /// Gets a list of users who have updated their device identity keys since a - /// previous sync token. - /// - /// The server should include in the results any users who: - /// - /// * currently share a room with the calling user (ie, both users have - /// membership state ``join``); *and* - /// * added new device identity keys or removed an existing device with - /// identity keys, between ``from`` and ``to``. - class GetKeysChangesJob : public BaseJob + /// If the homeserver could be reached, but the user or device + /// was unknown, no failure is recorded. Instead, the corresponding + /// user or device is missing from the `one_time_keys` result. + QHash<QString, QJsonObject> failures() const { - public: - /*! Query users with recent device key updates. - * \param from - * The desired start point of the list. Should be the ``next_batch`` field - * from a response to an earlier call to |/sync|. Users who have not - * uploaded new device identity keys since this point, nor deleted - * existing devices with identity keys since then, will be excluded - * from the results. - * \param to - * The desired end point of the list. Should be the ``next_batch`` - * field from a recent call to |/sync| - typically the most recent - * such call. This may be used by the server as a hint to check its - * caches are up to date. - */ - explicit GetKeysChangesJob(const QString& from, const QString& to); - - /*! Construct a URL without creating a full-fledged job object - * - * This function can be used when a URL for - * GetKeysChangesJob is necessary but the job - * itself isn't. - */ - static QUrl makeRequestUrl(QUrl baseUrl, const QString& from, const QString& to); - - ~GetKeysChangesJob() override; - - // Result properties - - /// The Matrix User IDs of all users who updated their device - /// identity keys. - const QStringList& changed() const; - /// The Matrix User IDs of all users who may have left all - /// the end-to-end encrypted rooms they previously shared - /// with the user. - const QStringList& left() const; - - protected: - Status parseJson(const QJsonDocument& data) override; - - private: - class Private; - QScopedPointer<Private> d; - }; -} // namespace QMatrixClient + return loadFromJson<QHash<QString, QJsonObject>>("failures"_ls); + } + + /// One-time keys for the queried devices. A map from user ID, to a + /// map from devices to a map from `<algorithm>:<key_id>` to the key object. + /// + /// See the [key algorithms](/client-server-api/#key-algorithms) section for + /// information on the Key Object format. + /// + /// If necessary, the claimed key might be a fallback key. Fallback + /// keys are re-used by the server until replaced by the device. + QHash<QString, QHash<QString, OneTimeKeys>> oneTimeKeys() const + { + return loadFromJson<QHash<QString, QHash<QString, OneTimeKeys>>>( + "one_time_keys"_ls); + } +}; + +/*! \brief Query users with recent device key updates. + * + * Gets a list of users who have updated their device identity keys since a + * previous sync token. + * + * The server should include in the results any users who: + * + * * currently share a room with the calling user (ie, both users have + * membership state `join`); *and* + * * added new device identity keys or removed an existing device with + * identity keys, between `from` and `to`. + */ +class QUOTIENT_API GetKeysChangesJob : public BaseJob { +public: + /*! \brief Query users with recent device key updates. + * + * \param from + * The desired start point of the list. Should be the `next_batch` field + * from a response to an earlier call to + * [`/sync`](/client-server-api/#get_matrixclientv3sync). Users who have not + * uploaded new device identity keys since this point, nor deleted + * existing devices with identity keys since then, will be excluded + * from the results. + * + * \param to + * The desired end point of the list. Should be the `next_batch` + * field from a recent call to + * [`/sync`](/client-server-api/#get_matrixclientv3sync) - typically the + * most recent such call. This may be used by the server as a hint to check + * its caches are up to date. + */ + explicit GetKeysChangesJob(const QString& from, const QString& to); + + /*! \brief Construct a URL without creating a full-fledged job object + * + * This function can be used when a URL for GetKeysChangesJob + * is necessary but the job itself isn't. + */ + static QUrl makeRequestUrl(QUrl baseUrl, const QString& from, + const QString& to); + + // Result properties + + /// The Matrix User IDs of all users who updated their device + /// identity keys. + QStringList changed() const + { + return loadFromJson<QStringList>("changed"_ls); + } + + /// The Matrix User IDs of all users who may have left all + /// the end-to-end encrypted rooms they previously shared + /// with the user. + QStringList left() const { return loadFromJson<QStringList>("left"_ls); } +}; + +} // namespace Quotient |