diff --git a/cmake/Hunter/config.cmake b/cmake/Hunter/config.cmake index 7c53e0ea57096a3372bf3779dfdf86e8958e114e..4cdeee97ba09d684988a241aa5af943d5793550d 100644 --- a/cmake/Hunter/config.cmake +++ b/cmake/Hunter/config.cmake @@ -3,3 +3,7 @@ hunter_config( VERSION "1.70.0-p1" CMAKE_ARGS IOSTREAMS_NO_BZIP2=1 ) +hunter_config( + nlohmann_json + CMAKE_ARGS JSON_MultipleHeaders=ON +) diff --git a/examples/crypto_bot.cpp b/examples/crypto_bot.cpp index eb4f2736ed5be28d6bf51d2e834778c4d709f19f..5c4b94247deee60f3780a5ba9dda0b4bfb3847eb 100644 --- a/examples/crypto_bot.cpp +++ b/examples/crypto_bot.cpp @@ -677,7 +677,7 @@ parse_messages(const mtx::responses::Sync &res) auto room_id = room.first; console->info("joining room {}", room_id); - client->join_room(room_id, [room_id](const nlohmann::json &, RequestErr e) { + client->join_room(room_id, [room_id](const mtx::responses::RoomId &, RequestErr e) { if (e) { print_errors(e); console->error("failed to join room {}", room_id); @@ -911,10 +911,10 @@ handle_to_device_msgs(const mtx::responses::ToDevice &msgs) console->info("inspecting {} to_device messages", msgs.events.size()); for (const auto &msg : msgs.events) { - console->info(std::visit(mtx::events::DeviceEventVisitor{}, msg).dump(2)); + console->info(std::visit([](const auto &e) { return json(e); }, msg).dump(2)); try { - OlmMessage olm_msg = std::visit(DeviceEventVisitor{}, msg); + OlmMessage olm_msg = std::visit([](const auto &e) { return json(e); }, msg); decrypt_olm_message(std::move(olm_msg)); } catch (const nlohmann::json::exception &e) { console->warn("parsing error for olm message: {}", e.what()); @@ -961,15 +961,13 @@ login_cb(const mtx::responses::Login &, RequestErr err) } void -join_room_cb(const nlohmann::json &obj, RequestErr err) +join_room_cb(const mtx::responses::RoomId &, RequestErr err) { if (err) { print_errors(err); return; } - (void)obj; - // Fetch device list for all users. } diff --git a/examples/media_downloader.cpp b/examples/media_downloader.cpp index 17b354a301cbd319c9b6ef49cfd3e56b869c38e2..42ddc2f2559be79f4b98536597e0df4c02b07f1f 100644 --- a/examples/media_downloader.cpp +++ b/examples/media_downloader.cpp @@ -150,7 +150,7 @@ message_handler(const mtx::responses::Messages &res, RequestErr err) return; } - for (const auto& msg : res.chunk) + for (const auto &msg : res.chunk) print_message(msg); if (res.chunk.empty()) { diff --git a/examples/room_feed.cpp b/examples/room_feed.cpp index 4fc826756024b9d639de724c16f87026d584ec5b..a81c03e2595f0d3de1c0ffd52b468b501c3a2ab2 100644 --- a/examples/room_feed.cpp +++ b/examples/room_feed.cpp @@ -96,8 +96,8 @@ sync_handler(const mtx::responses::Sync &res, RequestErr err) return; } - for (const auto& room : res.rooms.join) { - for (const auto& msg : room.second.timeline.events) + for (const auto &room : res.rooms.join) { + for (const auto &msg : room.second.timeline.events) print_message(msg); } diff --git a/examples/simple_bot.cpp b/examples/simple_bot.cpp index 5ed3f839d58e1c54b5048236a5c70e40d467b50e..0e2a47490146d03aafc9dd78a7ad66a36b8cb162 100644 --- a/examples/simple_bot.cpp +++ b/examples/simple_bot.cpp @@ -83,38 +83,41 @@ get_sender(const TimelineEvent &event) void parse_messages(const mtx::responses::Sync &res, bool parse_repeat_cmd = false) { - for (const auto& room : res.rooms.invite) { + for (const auto &room : res.rooms.invite) { auto room_id = room.first; printf("joining room %s\n", room_id.c_str()); - client->join_room(room_id, [room_id](const nlohmann::json &obj, RequestErr e) { - if (e) { - print_errors(e); - printf("failed to join room %s\n", room_id.c_str()); - return; - } - - printf("joined room \n%s\n", obj.dump(2).c_str()); - - mtx::events::msg::Text text; - text.body = "Thanks for the invitation!"; - - client->send_room_message<mtx::events::msg::Text>( - room_id, text, [room_id](const mtx::responses::EventId &, RequestErr e) { - if (e) { - print_errors(e); - return; - } - - printf("sent message to %s\n", room_id.c_str()); - }); - }); + client->join_room( + room_id, [room_id](const mtx::responses::RoomId &obj, RequestErr e) { + if (e) { + print_errors(e); + printf("failed to join room %s\n", room_id.c_str()); + return; + } + + printf("joined room \n%s\n", obj.room_id.c_str()); + + mtx::events::msg::Text text; + text.body = "Thanks for the invitation!"; + + client->send_room_message<mtx::events::msg::Text>( + room_id, + text, + [room_id](const mtx::responses::EventId &, RequestErr e) { + if (e) { + print_errors(e); + return; + } + + printf("sent message to %s\n", room_id.c_str()); + }); + }); } if (!parse_repeat_cmd) return; - for (const auto& room : res.rooms.join) { + for (const auto &room : res.rooms.join) { const std::string repeat_cmd = "!repeat"; const std::string room_id = room.first; diff --git a/include/mtx/common.hpp b/include/mtx/common.hpp index 452765427fb35c287377676de7eb1d1589e7eaf8..31ca50934fa0a32fb39250cfec3dab6794537e0f 100644 --- a/include/mtx/common.hpp +++ b/include/mtx/common.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <map> #include <string> diff --git a/include/mtx/errors.hpp b/include/mtx/errors.hpp index a4e75d76986421c6e837ea20e7a7a5da70cb5005..1dd8127f2e022031dc095dd23aa82a01c5fb7258 100644 --- a/include/mtx/errors.hpp +++ b/include/mtx/errors.hpp @@ -1,62 +1,10 @@ #pragma once -#include <nlohmann/json.hpp> -#include <string> - +#include "lightweight_error.hpp" #include "user_interactive.hpp" namespace mtx { namespace errors { - -enum class ErrorCode -{ - M_UNRECOGNIZED, - //! unknown user or so - M_UNKNOWN, - //! Forbidden access, e.g. joining a room without permission, failed login. - M_FORBIDDEN, - //! The access token specified was not recognised. - M_UNKNOWN_TOKEN, - //! Request contained valid JSON, but it was malformed in some way, - //! e.g. missing required keys, invalid values for keys - M_BAD_JSON, - //! Request did not contain valid JSON. - M_NOT_JSON, - //! No resource was found for this request. - M_NOT_FOUND, - //! Too many requests have been sent in a short period of time. - M_LIMIT_EXCEEDED, - //! Encountered when trying to register a user ID which has been taken. - M_USER_IN_USE, - //! Encountered when trying to register a user ID which is not valid. - M_INVALID_USERNAME, - //! Sent when the room alias given to the createRoom API is already in use. - M_ROOM_IN_USE, - //! Sent when the intial state given to the createRoom API is invalid. - M_INVALID_ROOM_STATE, - //! Encountered when specifying bad pagination query parameters. - M_BAD_PAGINATION, - //! Sent when a threepid given to an API cannot be used because - //! the same threepid is already in use. - M_THREEPID_IN_USE, - //! Sent when a threepid given to an API cannot be used - //! because no record matching the threepid was found. - M_THREEPID_NOT_FOUND, - //! The client's request used a third party server, - //! eg. ID server, that this server does not trust. - M_SERVER_NOT_TRUSTED, - //! The access token isn't present in the request. - M_MISSING_TOKEN, - //! One of the uploaded signatures was invalid - M_INVALID_SIGNATURE, -}; - -std::string -to_string(ErrorCode code); - -ErrorCode -from_string(const std::string &code); - //! Represents a Matrix related error. struct Error { diff --git a/include/mtx/events.hpp b/include/mtx/events.hpp index 9160d7e08ed1f6391c550a64077173bd129dfac9..36bb8384ed9c5053f9e4c179cb54df3f84bc5b83 100644 --- a/include/mtx/events.hpp +++ b/include/mtx/events.hpp @@ -1,7 +1,12 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif +#include "mtx/events/event_type.hpp" #include "mtx/events/messages/image.hpp" #include "mtx/events/redaction.hpp" #include "mtx/identifiers.hpp" @@ -9,101 +14,6 @@ using json = nlohmann::json; namespace mtx { namespace events { - -enum class EventType -{ - /// m.key.verification.cancel - KeyVerificationCancel, - /// m.key.verification.request - KeyVerificationRequest, - /// m.key.verification.start - KeyVerificationStart, - /// m.key.verification.accept - KeyVerificationAccept, - /// m.key.verification.key - KeyVerificationKey, - /// m.key.verification.mac - KeyVerificationMac, - /// m.key.verification.ready, - KeyVerificationReady, - /// m.key.verification.done, - KeyVerificationDone, - /// m.reaction, - Reaction, - /// m.room_key - RoomKey, - /// m.forwarded_room_key - ForwardedRoomKey, - /// m.room_key_request - RoomKeyRequest, - /// m.room.aliases - RoomAliases, - /// m.room.avatar - RoomAvatar, - /// m.room.canonical_alias - RoomCanonicalAlias, - /// m.room.create - RoomCreate, - /// m.room.encrypted. - RoomEncrypted, - /// m.room.encryption. - RoomEncryption, - /// m.room.guest_access - RoomGuestAccess, - /// m.room.history_visibility - RoomHistoryVisibility, - /// m.room.join_rules - RoomJoinRules, - /// m.room.member - RoomMember, - /// m.room.message - RoomMessage, - /// m.room.name - RoomName, - /// m.room.power_levels - RoomPowerLevels, - /// m.room.topic - RoomTopic, - /// m.room.redaction - RoomRedaction, - /// m.room.pinned_events - RoomPinnedEvents, - /// m.room.tombstone - RoomTombstone, - // m.sticker - Sticker, - // m.tag - Tag, - // m.presence - Presence, - // m.push_rules - PushRules, - // m.call.invite - CallInvite, - // m.call.candidates - CallCandidates, - // m.call.answer - CallAnswer, - // m.call.hangup - CallHangUp, - - // custom events - // im.nheko.hidden_events - NhekoHiddenEvents, - - // Unsupported event - Unsupported, -}; - -std::string -to_string(EventType type); - -EventType -getEventType(const std::string &type); - -EventType -getEventType(const json &obj); - //! The basic set of fields all events must have. template<class Content> struct Event @@ -121,21 +31,11 @@ struct Event template<class Content> void -to_json(json &obj, const Event<Content> &event) -{ - obj["content"] = event.content; - obj["sender"] = event.sender; - obj["type"] = ::mtx::events::to_string(event.type); -} +to_json(json &obj, const Event<Content> &event); template<class Content> void -from_json(const json &obj, Event<Content> &event) -{ - event.content = obj.at("content").get<Content>(); - event.type = getEventType(obj.at("type").get<std::string>()); - event.sender = obj.value("sender", ""); -} +from_json(const json &obj, Event<Content> &event); //! Extension of the Event type for device events. template<class Content> @@ -146,24 +46,11 @@ struct DeviceEvent : public Event<Content> template<class Content> void -from_json(const json &obj, DeviceEvent<Content> &event) -{ - Event<Content> base_event = event; - from_json(obj, base_event); - event.content = base_event.content; - event.type = base_event.type; - event.sender = obj.at("sender"); -} +from_json(const json &obj, DeviceEvent<Content> &event); template<class Content> void -to_json(json &obj, const DeviceEvent<Content> &event) -{ - Event<Content> base_event = event; - to_json(obj, base_event); - - obj["sender"] = event.sender; -} +to_json(json &obj, const DeviceEvent<Content> &event); struct UnsignedData { @@ -184,50 +71,11 @@ struct UnsignedData std::optional<Event<mtx::events::msg::Redaction>> redacted_because; }; -inline void -from_json(const json &obj, UnsignedData &data) -{ - if (obj.find("age") != obj.end()) - data.age = obj.at("age").get<uint64_t>(); - - if (obj.find("transaction_id") != obj.end()) - data.transaction_id = obj.at("transaction_id").get<std::string>(); - - if (obj.find("prev_sender") != obj.end()) - data.prev_sender = obj.at("prev_sender").get<std::string>(); - - if (obj.find("replaces_state") != obj.end()) - data.replaces_state = obj.at("replaces_state").get<std::string>(); - - if (obj.find("redacted_by") != obj.end()) - data.redacted_by = obj.at("redacted_by").get<std::string>(); - - if (obj.find("redacted_because") != obj.end()) - data.redacted_because = - obj.at("redacted_because").get<Event<mtx::events::msg::Redaction>>(); -} - -inline void -to_json(json &obj, const UnsignedData &event) -{ - if (!event.prev_sender.empty()) - obj["prev_sender"] = event.prev_sender; - - if (!event.transaction_id.empty()) - obj["transaction_id"] = event.transaction_id; - - if (!event.replaces_state.empty()) - obj["replaces_state"] = event.replaces_state; - - if (event.age != 0) - obj["age"] = event.age; - - if (!event.redacted_by.empty()) - obj["redacted_by"] = event.redacted_by; +void +from_json(const json &obj, UnsignedData &data); - if (event.redacted_because) - obj["redacted_because"] = *event.redacted_because; -} +void +to_json(json &obj, const UnsignedData &event); template<class Content> struct StrippedEvent : public Event<Content> @@ -237,23 +85,11 @@ struct StrippedEvent : public Event<Content> template<class Content> void -from_json(const json &obj, StrippedEvent<Content> &event) -{ - Event<Content> &base = event; - from_json(obj, base); - - event.state_key = obj.at("state_key"); -} +from_json(const json &obj, StrippedEvent<Content> &event); template<class Content> void -to_json(json &obj, const StrippedEvent<Content> &event) -{ - Event<Content> base_event = event; - to_json(obj, base_event); - - obj["state_key"] = event.state_key; -} +to_json(json &obj, const StrippedEvent<Content> &event); //! RoomEvent. template<class Content> @@ -273,36 +109,11 @@ struct RoomEvent : public Event<Content> template<class Content> void -from_json(const json &obj, RoomEvent<Content> &event) -{ - Event<Content> &base = event; - from_json(obj, base); - - event.event_id = obj.at("event_id"); - event.origin_server_ts = obj.at("origin_server_ts"); - - // SPEC_BUG: Not present in the state array returned by /sync. - if (obj.find("room_id") != obj.end()) - event.room_id = obj.at("room_id"); - - if (obj.find("unsigned") != obj.end()) - event.unsigned_data = obj.at("unsigned"); -} +from_json(const json &obj, RoomEvent<Content> &event); template<class Content> void -to_json(json &obj, const RoomEvent<Content> &event) -{ - Event<Content> base_event = event; - to_json(obj, base_event); - - if (!event.room_id.empty()) - obj["room_id"] = event.room_id; - - obj["event_id"] = event.event_id; - obj["unsigned"] = event.unsigned_data; - obj["origin_server_ts"] = event.origin_server_ts; -} +to_json(json &obj, const RoomEvent<Content> &event); //! Extension of the RoomEvent. template<class Content> @@ -315,23 +126,11 @@ struct StateEvent : public RoomEvent<Content> template<class Content> void -to_json(json &obj, const StateEvent<Content> &event) -{ - RoomEvent<Content> base_event = event; - to_json(obj, base_event); - - obj["state_key"] = event.state_key; -} +to_json(json &obj, const StateEvent<Content> &event); template<class Content> void -from_json(const json &obj, StateEvent<Content> &event) -{ - RoomEvent<Content> &base = event; - from_json(obj, base); - - event.state_key = obj.at("state_key").get<std::string>(); -} +from_json(const json &obj, StateEvent<Content> &event); //! Extension of the RoomEvent. template<class Content> @@ -343,23 +142,11 @@ struct RedactionEvent : public RoomEvent<Content> template<class Content> void -to_json(json &obj, const RedactionEvent<Content> &event) -{ - RoomEvent<Content> base_event = event; - to_json(obj, base_event); - - obj["redacts"] = event.redacts; -} +to_json(json &obj, const RedactionEvent<Content> &event); template<class Content> void -from_json(const json &obj, RedactionEvent<Content> &event) -{ - RoomEvent<Content> &base = event; - from_json(obj, base); - - event.redacts = obj.at("redacts").get<std::string>(); -} +from_json(const json &obj, RedactionEvent<Content> &event); //! Extension of the RoomEvent. template<class Content> @@ -368,19 +155,11 @@ struct EncryptedEvent : public RoomEvent<Content> template<class Content> void -to_json(json &obj, const EncryptedEvent<Content> &event) -{ - RoomEvent<Content> base_event = event; - to_json(obj, base_event); -} +to_json(json &obj, const EncryptedEvent<Content> &event); template<class Content> void -from_json(const json &obj, EncryptedEvent<Content> &event) -{ - RoomEvent<Content> &base = event; - from_json(obj, base); -} +from_json(const json &obj, EncryptedEvent<Content> &event); enum class MessageType { diff --git a/include/mtx/events/aliases.hpp b/include/mtx/events/aliases.hpp index 6e680bf99102293729f57de9c7a705c6c5656cae..64a68c4c302d908b29cba2bf005f28cc51364acb 100644 --- a/include/mtx/events/aliases.hpp +++ b/include/mtx/events/aliases.hpp @@ -3,7 +3,11 @@ #include <string> #include <vector> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif namespace mtx { namespace events { diff --git a/include/mtx/events/avatar.hpp b/include/mtx/events/avatar.hpp index a9071ce2376cc9f6205df9791ad0e44cf1bb48ae..1a7c7e1a6b7547c5487b468453e705f11812813f 100644 --- a/include/mtx/events/avatar.hpp +++ b/include/mtx/events/avatar.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include "mtx/events/common.hpp" diff --git a/include/mtx/events/canonical_alias.hpp b/include/mtx/events/canonical_alias.hpp index d9dcb8308a2f959f2fd713f14efcef9373304670..ed19abd558bd64753b8ff2d86395f59f986929a8 100644 --- a/include/mtx/events/canonical_alias.hpp +++ b/include/mtx/events/canonical_alias.hpp @@ -2,7 +2,11 @@ #include <string> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif namespace mtx { namespace events { diff --git a/include/mtx/events/common.hpp b/include/mtx/events/common.hpp index 269f7a06bf191694f2c3f1695b75052bea3917b8..ea6cd4afa212f83f17f0059f488bb3d3ff6d8198 100644 --- a/include/mtx/events/common.hpp +++ b/include/mtx/events/common.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <optional> diff --git a/include/mtx/events/create.hpp b/include/mtx/events/create.hpp index 8e831305f5c69f2d8b348358255b9342d10a456e..69cf3831fae7729439e5e5183c3eb7d4276de577 100644 --- a/include/mtx/events/create.hpp +++ b/include/mtx/events/create.hpp @@ -2,7 +2,11 @@ #include <optional> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif namespace mtx { namespace events { diff --git a/include/mtx/events/encrypted.hpp b/include/mtx/events/encrypted.hpp index 3180c250db4de462a2d8b1134a8fe24c479b954f..625bc747d6fb7760f1dcf72ceb227c71fa0d10a9 100644 --- a/include/mtx/events/encrypted.hpp +++ b/include/mtx/events/encrypted.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include "mtx/events.hpp" #include "mtx/events/common.hpp" @@ -392,94 +396,5 @@ void to_json(nlohmann::json &obj, const KeyVerificationMac &event); } // namespace msg -struct DeviceEventVisitor -{ - nlohmann::json operator()(const DeviceEvent<mtx::events::msg::RoomKey> &roomKey) - { - json j; - mtx::events::to_json(j, roomKey); - return j; - } - nlohmann::json operator()(const DeviceEvent<mtx::events::msg::ForwardedRoomKey> &roomKey) - { - json j; - mtx::events::to_json(j, roomKey); - return j; - } - nlohmann::json operator()(const DeviceEvent<mtx::events::msg::KeyRequest> &keyReq) - { - json j; - mtx::events::to_json(j, keyReq); - return j; - } - nlohmann::json operator()(const DeviceEvent<mtx::events::msg::OlmEncrypted> &olmEnc) - { - json j; - mtx::events::to_json(j, olmEnc); - return j; - } - nlohmann::json operator()(const DeviceEvent<mtx::events::msg::Encrypted> &enc) - { - json j; - mtx::events::to_json(j, enc); - return j; - } - nlohmann::json operator()( - const DeviceEvent<mtx::events::msg::KeyVerificationRequest> &keyVerificationRequest) - { - json j; - mtx::events::to_json(j, keyVerificationRequest); - return j; - } - nlohmann::json operator()( - const DeviceEvent<mtx::events::msg::KeyVerificationAccept> &keyVerificationAccept) - { - json j; - mtx::events::to_json(j, keyVerificationAccept); - return j; - } - nlohmann::json operator()( - const DeviceEvent<mtx::events::msg::KeyVerificationStart> &keyVerificationStart) - { - json j; - mtx::events::to_json(j, keyVerificationStart); - return j; - } - nlohmann::json operator()( - const DeviceEvent<mtx::events::msg::KeyVerificationCancel> &KeyVerificationCancel) - { - json j; - mtx::events::to_json(j, KeyVerificationCancel); - return j; - } - nlohmann::json operator()( - const DeviceEvent<mtx::events::msg::KeyVerificationKey> &keyVerificationKey) - { - json j; - mtx::events::to_json(j, keyVerificationKey); - return j; - } - nlohmann::json operator()( - const DeviceEvent<mtx::events::msg::KeyVerificationMac> &keyVerificationMac) - { - json j; - mtx::events::to_json(j, keyVerificationMac); - return j; - } - nlohmann::json operator()( - const DeviceEvent<mtx::events::msg::KeyVerificationReady> &keyVerificationReady) - { - json j; - mtx::events::to_json(j, keyVerificationReady); - return j; - } - nlohmann::json operator()( - const DeviceEvent<mtx::events::msg::KeyVerificationDone> &keyVerificationDone) - { - json j; - mtx::events::to_json(j, keyVerificationDone); - return j; - } -}; } // namespace events } // namespace mtx diff --git a/include/mtx/events/encryption.hpp b/include/mtx/events/encryption.hpp index f7e86ba592a05f42ee4c38b417be41872687f273..b8c021647e65d4fc6bc18b86c2a03c645de47d78 100644 --- a/include/mtx/events/encryption.hpp +++ b/include/mtx/events/encryption.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif namespace mtx { namespace events { diff --git a/include/mtx/events/event_type.hpp b/include/mtx/events/event_type.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8ef332721bd57a8cba3313b8a95be7692d82a159 --- /dev/null +++ b/include/mtx/events/event_type.hpp @@ -0,0 +1,107 @@ +#pragma once + +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else +#include <nlohmann/json.hpp> +#endif + +#include <string> +namespace mtx { +namespace events { + +enum class EventType +{ + /// m.key.verification.cancel + KeyVerificationCancel, + /// m.key.verification.request + KeyVerificationRequest, + /// m.key.verification.start + KeyVerificationStart, + /// m.key.verification.accept + KeyVerificationAccept, + /// m.key.verification.key + KeyVerificationKey, + /// m.key.verification.mac + KeyVerificationMac, + /// m.key.verification.ready, + KeyVerificationReady, + /// m.key.verification.done, + KeyVerificationDone, + /// m.reaction, + Reaction, + /// m.room_key + RoomKey, + /// m.forwarded_room_key + ForwardedRoomKey, + /// m.room_key_request + RoomKeyRequest, + /// m.room.aliases + RoomAliases, + /// m.room.avatar + RoomAvatar, + /// m.room.canonical_alias + RoomCanonicalAlias, + /// m.room.create + RoomCreate, + /// m.room.encrypted. + RoomEncrypted, + /// m.room.encryption. + RoomEncryption, + /// m.room.guest_access + RoomGuestAccess, + /// m.room.history_visibility + RoomHistoryVisibility, + /// m.room.join_rules + RoomJoinRules, + /// m.room.member + RoomMember, + /// m.room.message + RoomMessage, + /// m.room.name + RoomName, + /// m.room.power_levels + RoomPowerLevels, + /// m.room.topic + RoomTopic, + /// m.room.redaction + RoomRedaction, + /// m.room.pinned_events + RoomPinnedEvents, + /// m.room.tombstone + RoomTombstone, + // m.sticker + Sticker, + // m.tag + Tag, + // m.presence + Presence, + // m.push_rules + PushRules, + // m.call.invite + CallInvite, + // m.call.candidates + CallCandidates, + // m.call.answer + CallAnswer, + // m.call.hangup + CallHangUp, + + // custom events + // im.nheko.hidden_events + NhekoHiddenEvents, + + // Unsupported event + Unsupported, +}; + +std::string +to_string(EventType type); + +EventType +getEventType(const std::string &type); + +EventType +getEventType(const nlohmann::json &obj); +} +} diff --git a/include/mtx/events/guest_access.hpp b/include/mtx/events/guest_access.hpp index 4f3d31051d78f90f4fcc13c6bf9d7020603317ce..2718f82431683c75d7bb4552fb1d79f4de464dbc 100644 --- a/include/mtx/events/guest_access.hpp +++ b/include/mtx/events/guest_access.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> diff --git a/include/mtx/events/history_visibility.hpp b/include/mtx/events/history_visibility.hpp index 30bf911b4cfe035c81af07bd39e1b369ce33b64e..ddc8cc4a5838c42685bbf6d0801f6d4762f655df 100644 --- a/include/mtx/events/history_visibility.hpp +++ b/include/mtx/events/history_visibility.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> diff --git a/include/mtx/events/join_rules.hpp b/include/mtx/events/join_rules.hpp index e8aab20cfbeb16cfb99c410364745fd90fbcbc5f..63473fd28197c1e95e7257cf8ce4465a429153af 100644 --- a/include/mtx/events/join_rules.hpp +++ b/include/mtx/events/join_rules.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> diff --git a/include/mtx/events/member.hpp b/include/mtx/events/member.hpp index 80ed56c588f465d8e189b5fe0ff17cd90e085681..25fb66a9bf5423477f629ca59212294c9194aba2 100644 --- a/include/mtx/events/member.hpp +++ b/include/mtx/events/member.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> diff --git a/include/mtx/events/messages/audio.hpp b/include/mtx/events/messages/audio.hpp index c16802337f427480ceef17b265e05c0d58e2fb2a..501ff94e0b789d2250266b4a6b447eaaff5a1913 100644 --- a/include/mtx/events/messages/audio.hpp +++ b/include/mtx/events/messages/audio.hpp @@ -3,7 +3,11 @@ #include <optional> #include <string> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include "mtx/common.hpp" #include "mtx/events/common.hpp" diff --git a/include/mtx/events/messages/emote.hpp b/include/mtx/events/messages/emote.hpp index 67f4e98c3be15b1969583d8e1108ce16702ac1ce..6061c7cbf7231a826d161b962e9e4aadb03091b6 100644 --- a/include/mtx/events/messages/emote.hpp +++ b/include/mtx/events/messages/emote.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> diff --git a/include/mtx/events/messages/file.hpp b/include/mtx/events/messages/file.hpp index 4cbe285f387a4a343d06cb147093f8f25885c4af..c029e9cd8eded757033ef00672bda8e8ac79a911 100644 --- a/include/mtx/events/messages/file.hpp +++ b/include/mtx/events/messages/file.hpp @@ -3,7 +3,11 @@ #include <optional> #include <string> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include "mtx/common.hpp" #include "mtx/events/common.hpp" diff --git a/include/mtx/events/messages/image.hpp b/include/mtx/events/messages/image.hpp index 3188566a5173e1e28d4d55d0215ad2d439deb6cb..00619d953583103451b9e40912cb7f6a8221be41 100644 --- a/include/mtx/events/messages/image.hpp +++ b/include/mtx/events/messages/image.hpp @@ -3,7 +3,11 @@ #include <optional> #include <string> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include "mtx/common.hpp" #include "mtx/events/common.hpp" diff --git a/include/mtx/events/messages/notice.hpp b/include/mtx/events/messages/notice.hpp index b1783deb819313abc5eef0f986d2d1371d34bf65..7e89ee3caee39523e2820ea83f15b8048fd12f24 100644 --- a/include/mtx/events/messages/notice.hpp +++ b/include/mtx/events/messages/notice.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> diff --git a/include/mtx/events/messages/text.hpp b/include/mtx/events/messages/text.hpp index 2b55014f1e402ba26a6e0bbbd12830c10f0d63ca..1a929f3535c3ec540a77bc6b4b7630606285da47 100644 --- a/include/mtx/events/messages/text.hpp +++ b/include/mtx/events/messages/text.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> diff --git a/include/mtx/events/messages/video.hpp b/include/mtx/events/messages/video.hpp index d7009307f8dbb63d6856c2d5520f4317841a5b44..2af4b1eb8f666876eaff29c08ebea38c0ad87c0b 100644 --- a/include/mtx/events/messages/video.hpp +++ b/include/mtx/events/messages/video.hpp @@ -3,7 +3,11 @@ #include <optional> #include <string> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include "mtx/common.hpp" #include "mtx/events/common.hpp" diff --git a/include/mtx/events/name.hpp b/include/mtx/events/name.hpp index 292f9d16c97b4d34f5759cd63840965e0710d0bd..67fdbadec5252e6d767924814b466e3553fe6c91 100644 --- a/include/mtx/events/name.hpp +++ b/include/mtx/events/name.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> diff --git a/include/mtx/events/nheko_extensions/hidden_events.hpp b/include/mtx/events/nheko_extensions/hidden_events.hpp index ef69854c9f86cd957bac564e5a1e76708cfb0d1c..7eb92578a505e03a821f218179ea24bd3ea8b92d 100644 --- a/include/mtx/events/nheko_extensions/hidden_events.hpp +++ b/include/mtx/events/nheko_extensions/hidden_events.hpp @@ -2,7 +2,11 @@ #include <vector> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include "mtx/events.hpp" diff --git a/include/mtx/events/pinned_events.hpp b/include/mtx/events/pinned_events.hpp index 51a58bb0eca0ce105000363173f96cde7c8c2f59..c5e64606a08eb401d1eb3e4914d032e887e598bc 100644 --- a/include/mtx/events/pinned_events.hpp +++ b/include/mtx/events/pinned_events.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> diff --git a/include/mtx/events/power_levels.hpp b/include/mtx/events/power_levels.hpp index ea6c7703404eced1f99e3c377e7f5dcbaf055a74..375e67032304bd362208db3dc23eb79904d532ba 100644 --- a/include/mtx/events/power_levels.hpp +++ b/include/mtx/events/power_levels.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> diff --git a/include/mtx/events/presence.hpp b/include/mtx/events/presence.hpp index 4ce9d1490f363a53c015ed1f9036a113fe384c45..34fbc191d365cbff3c90eea7f1bcf58d69266a79 100644 --- a/include/mtx/events/presence.hpp +++ b/include/mtx/events/presence.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <optional> #include <string> diff --git a/include/mtx/events/reaction.hpp b/include/mtx/events/reaction.hpp index 742f8ff8266d63d24eaa85da3064b453e5ee3413..1ba22a1fc59ce598e59447808c8c32fb54031c3d 100644 --- a/include/mtx/events/reaction.hpp +++ b/include/mtx/events/reaction.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> diff --git a/include/mtx/events/redaction.hpp b/include/mtx/events/redaction.hpp index 077c55dfce3ddff2092ce7a05068ba32e0ba5937..c7bd339b69d4c6f8d192cf5c05363be5a096352f 100644 --- a/include/mtx/events/redaction.hpp +++ b/include/mtx/events/redaction.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> diff --git a/include/mtx/events/tag.hpp b/include/mtx/events/tag.hpp index 728bb4729ed011d2ac25e5c6859c1925184b2d6c..1eb78a02fde44ff8dfa06a4b68b7e21934e8b7ca 100644 --- a/include/mtx/events/tag.hpp +++ b/include/mtx/events/tag.hpp @@ -3,7 +3,11 @@ #include <optional> #include <string> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif namespace mtx { namespace events { diff --git a/include/mtx/events/tombstone.hpp b/include/mtx/events/tombstone.hpp index 0243a8efdc1cfe90acc8e421c59400567157a866..f5d3de25bdc74a0efe05b7bd96fe3b4705759801 100644 --- a/include/mtx/events/tombstone.hpp +++ b/include/mtx/events/tombstone.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif namespace mtx { namespace events { diff --git a/include/mtx/events/topic.hpp b/include/mtx/events/topic.hpp index 34a89098d61e5937e8c33757c2c5718440544b70..5a1f2f04ce50277dd3012babe2d1b492a0875db2 100644 --- a/include/mtx/events/topic.hpp +++ b/include/mtx/events/topic.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> diff --git a/include/mtx/events/voip.hpp b/include/mtx/events/voip.hpp index 54c4c0aced3c6c7702b6a36f47f9bbdb6f93bf42..7ed17936602a4ce4213a489ad560a2cb2ef76689 100644 --- a/include/mtx/events/voip.hpp +++ b/include/mtx/events/voip.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> #include <vector> diff --git a/include/mtx/events_impl.hpp b/include/mtx/events_impl.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5f574a6b1f6f28796803c96ae9f5af7c50ea4b36 --- /dev/null +++ b/include/mtx/events_impl.hpp @@ -0,0 +1,199 @@ +#include "events.hpp" + +#include <nlohmann/json.hpp> + +namespace mtx::events { +template<class Content> +void +to_json(json &obj, const Event<Content> &event) +{ + obj["content"] = event.content; + obj["sender"] = event.sender; + obj["type"] = ::mtx::events::to_string(event.type); +} + +template<class Content> +void +from_json(const json &obj, Event<Content> &event) +{ + event.content = obj.at("content").get<Content>(); + event.type = getEventType(obj.at("type").get<std::string>()); + event.sender = obj.value("sender", ""); +} + +template<class Content> +void +from_json(const json &obj, DeviceEvent<Content> &event) +{ + Event<Content> base_event = event; + from_json(obj, base_event); + event.content = base_event.content; + event.type = base_event.type; + event.sender = obj.at("sender"); +} + +template<class Content> +void +to_json(json &obj, const DeviceEvent<Content> &event) +{ + Event<Content> base_event = event; + to_json(obj, base_event); + + obj["sender"] = event.sender; +} + +void +from_json(const json &obj, UnsignedData &data) +{ + if (obj.find("age") != obj.end()) + data.age = obj.at("age").get<uint64_t>(); + + if (obj.find("transaction_id") != obj.end()) + data.transaction_id = obj.at("transaction_id").get<std::string>(); + + if (obj.find("prev_sender") != obj.end()) + data.prev_sender = obj.at("prev_sender").get<std::string>(); + + if (obj.find("replaces_state") != obj.end()) + data.replaces_state = obj.at("replaces_state").get<std::string>(); + + if (obj.find("redacted_by") != obj.end()) + data.redacted_by = obj.at("redacted_by").get<std::string>(); + + if (obj.find("redacted_because") != obj.end()) + data.redacted_because = + obj.at("redacted_because").get<Event<mtx::events::msg::Redaction>>(); +} + +void +to_json(json &obj, const UnsignedData &event) +{ + if (!event.prev_sender.empty()) + obj["prev_sender"] = event.prev_sender; + + if (!event.transaction_id.empty()) + obj["transaction_id"] = event.transaction_id; + + if (!event.replaces_state.empty()) + obj["replaces_state"] = event.replaces_state; + + if (event.age != 0) + obj["age"] = event.age; + + if (!event.redacted_by.empty()) + obj["redacted_by"] = event.redacted_by; + + if (event.redacted_because) + obj["redacted_because"] = *event.redacted_because; +} + +template<class Content> +void +from_json(const json &obj, StrippedEvent<Content> &event) +{ + Event<Content> &base = event; + from_json(obj, base); + + event.state_key = obj.at("state_key"); +} + +template<class Content> +void +to_json(json &obj, const StrippedEvent<Content> &event) +{ + Event<Content> base_event = event; + to_json(obj, base_event); + + obj["state_key"] = event.state_key; +} + +template<class Content> +void +from_json(const json &obj, RoomEvent<Content> &event) +{ + Event<Content> &base = event; + from_json(obj, base); + + event.event_id = obj.at("event_id"); + event.origin_server_ts = obj.at("origin_server_ts"); + + // SPEC_BUG: Not present in the state array returned by /sync. + if (obj.find("room_id") != obj.end()) + event.room_id = obj.at("room_id"); + + if (obj.find("unsigned") != obj.end()) + event.unsigned_data = obj.at("unsigned"); +} + +template<class Content> +void +to_json(json &obj, const RoomEvent<Content> &event) +{ + Event<Content> base_event = event; + to_json(obj, base_event); + + if (!event.room_id.empty()) + obj["room_id"] = event.room_id; + + obj["event_id"] = event.event_id; + obj["unsigned"] = event.unsigned_data; + obj["origin_server_ts"] = event.origin_server_ts; +} + +template<class Content> +void +to_json(json &obj, const StateEvent<Content> &event) +{ + RoomEvent<Content> base_event = event; + to_json(obj, base_event); + + obj["state_key"] = event.state_key; +} + +template<class Content> +void +from_json(const json &obj, StateEvent<Content> &event) +{ + RoomEvent<Content> &base = event; + from_json(obj, base); + + event.state_key = obj.at("state_key").get<std::string>(); +} + +template<class Content> +void +to_json(json &obj, const RedactionEvent<Content> &event) +{ + RoomEvent<Content> base_event = event; + to_json(obj, base_event); + + obj["redacts"] = event.redacts; +} + +template<class Content> +void +from_json(const json &obj, RedactionEvent<Content> &event) +{ + RoomEvent<Content> &base = event; + from_json(obj, base); + + event.redacts = obj.at("redacts").get<std::string>(); +} + +template<class Content> +void +to_json(json &obj, const EncryptedEvent<Content> &event) +{ + RoomEvent<Content> base_event = event; + to_json(obj, base_event); +} + +template<class Content> +void +from_json(const json &obj, EncryptedEvent<Content> &event) +{ + RoomEvent<Content> &base = event; + from_json(obj, base); +} + +} diff --git a/include/mtx/identifiers.hpp b/include/mtx/identifiers.hpp index c0fa48c408a10f2272fa68cac63891efd1ae169b..b6ef59e576dd2d56055b2f4db7b0c666095708be 100644 --- a/include/mtx/identifiers.hpp +++ b/include/mtx/identifiers.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <stdexcept> diff --git a/include/mtx/lightweight_error.hpp b/include/mtx/lightweight_error.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dc207521ad3a5993098e32ccbf2aed39e3c5d072 --- /dev/null +++ b/include/mtx/lightweight_error.hpp @@ -0,0 +1,74 @@ +#pragma once + +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else +#include <nlohmann/json.hpp> +#endif +#include <string> + +namespace mtx { +namespace errors { + +enum class ErrorCode +{ + M_UNRECOGNIZED, + //! unknown user or so + M_UNKNOWN, + //! Forbidden access, e.g. joining a room without permission, failed login. + M_FORBIDDEN, + //! The access token specified was not recognised. + M_UNKNOWN_TOKEN, + //! Request contained valid JSON, but it was malformed in some way, + //! e.g. missing required keys, invalid values for keys + M_BAD_JSON, + //! Request did not contain valid JSON. + M_NOT_JSON, + //! No resource was found for this request. + M_NOT_FOUND, + //! Too many requests have been sent in a short period of time. + M_LIMIT_EXCEEDED, + //! Encountered when trying to register a user ID which has been taken. + M_USER_IN_USE, + //! Encountered when trying to register a user ID which is not valid. + M_INVALID_USERNAME, + //! Sent when the room alias given to the createRoom API is already in use. + M_ROOM_IN_USE, + //! Sent when the intial state given to the createRoom API is invalid. + M_INVALID_ROOM_STATE, + //! Encountered when specifying bad pagination query parameters. + M_BAD_PAGINATION, + //! Sent when a threepid given to an API cannot be used because + //! the same threepid is already in use. + M_THREEPID_IN_USE, + //! Sent when a threepid given to an API cannot be used + //! because no record matching the threepid was found. + M_THREEPID_NOT_FOUND, + //! The client's request used a third party server, + //! eg. ID server, that this server does not trust. + M_SERVER_NOT_TRUSTED, + //! The access token isn't present in the request. + M_MISSING_TOKEN, + //! One of the uploaded signatures was invalid + M_INVALID_SIGNATURE, +}; + +std::string +to_string(ErrorCode code); + +ErrorCode +from_string(const std::string &code); + +//! Represents a Matrix related error. +struct LightweightError +{ + //! Error code. + ErrorCode errcode = {}; + //! Human readable version of the error. + std::string error; +}; + +void +from_json(const nlohmann::json &obj, LightweightError &error); +} +} diff --git a/include/mtx/pushrules.hpp b/include/mtx/pushrules.hpp index ad73054351a0225f03606eb2605b58344b4e1bd1..f4301d96be4dfbe84574ccb0a1c3a0dda33ad4d9 100644 --- a/include/mtx/pushrules.hpp +++ b/include/mtx/pushrules.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> #include <variant> diff --git a/include/mtx/requests.hpp b/include/mtx/requests.hpp index 4a4fb0f54db39c86a045816de9e0d820449f6f77..e73586b7c136624bb29a0b1901db9c7acbd4e3e9 100644 --- a/include/mtx/requests.hpp +++ b/include/mtx/requests.hpp @@ -5,7 +5,11 @@ #include <mtx/common.hpp> #include <mtx/events/collections.hpp> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif using json = nlohmann::json; @@ -142,6 +146,17 @@ to_json(json &, const Empty &) using Logout = Empty; +struct SignedOneTimeKey +{ + //! Required. The unpadded Base64-encoded 32-byte Curve25519 public key. + std::string key; + //! Required. Signatures of the key object. + //! The signature is calculated using the process described at Signing JSON. + std::map<std::string, std::map<std::string, std::string>> signatures; +}; +void +to_json(json &obj, const SignedOneTimeKey &); + struct UploadKeys { //! Identity keys for the device. @@ -150,7 +165,7 @@ struct UploadKeys //! 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. - std::map<std::string, json> one_time_keys; + std::map<std::string, std::variant<std::string, SignedOneTimeKey>> one_time_keys; }; void @@ -185,12 +200,8 @@ struct ClaimKeys std::map<std::string, std::map<std::string, std::string>> one_time_keys; }; -inline void -to_json(json &obj, const ClaimKeys &request) -{ - obj["timeout"] = request.timeout; - obj["one_time_keys"] = request.one_time_keys; -} +void +to_json(json &obj, const ClaimKeys &request); struct KeySignaturesUpload { diff --git a/include/mtx/responses/common.hpp b/include/mtx/responses/common.hpp index b1422ad2b5ce552f122f3ef51e621b9382e38d79..574679157b94b11559cf4f7a73abad0507db7e7d 100644 --- a/include/mtx/responses/common.hpp +++ b/include/mtx/responses/common.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> #include <vector> @@ -26,6 +30,14 @@ struct GroupId void from_json(const nlohmann::json &obj, GroupId &response); +struct RoomId +{ + std::string room_id; +}; + +void +from_json(const nlohmann::json &obj, RoomId &response); + struct FilterId { std::string filter_id; @@ -46,7 +58,7 @@ namespace states = mtx::events::state; namespace msgs = mtx::events::msg; void -log_error(nlohmann::json::exception &err, const nlohmann::json &event); +log_error(std::exception &err, const nlohmann::json &event); void log_error(std::string err, const nlohmann::json &event); diff --git a/include/mtx/responses/create_room.hpp b/include/mtx/responses/create_room.hpp index d460785dd9675b4b6b509ad6a04215e88d1aec7d..e1fe6e10d364103f23d0944188880c21a680264b 100644 --- a/include/mtx/responses/create_room.hpp +++ b/include/mtx/responses/create_room.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif namespace mtx { namespace responses { diff --git a/include/mtx/responses/crypto.hpp b/include/mtx/responses/crypto.hpp index 0d72b8952c72f34e53b2eb96317bbb3694a3caca..358886bc64db82bf9ac6968ca01d8f617415f62c 100644 --- a/include/mtx/responses/crypto.hpp +++ b/include/mtx/responses/crypto.hpp @@ -1,9 +1,13 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include "mtx/common.hpp" -#include "mtx/errors.hpp" +#include "mtx/lightweight_error.hpp" #include <map> #include <string> @@ -51,7 +55,7 @@ from_json(const nlohmann::json &obj, QueryKeys &response); struct KeySignaturesUpload { - std::map<std::string, std::map<std::string, mtx::errors::Error>> errors; + std::map<std::string, std::map<std::string, mtx::errors::LightweightError>> errors; }; void @@ -158,7 +162,7 @@ struct BackupVersion std::string algorithm; //! Required. Algorithm-dependent data. See the documentation for the backup algorithms in //! Server-side key backups for more information on the expected format of the data. - nlohmann::json auth_data; + std::string auth_data; //! Required. The number of keys stored in the backup. int64_t count; //! Required. An opaque string representing stored keys in the backup. Clients can diff --git a/include/mtx/responses/empty.hpp b/include/mtx/responses/empty.hpp index 72d680926d199494a9352605df93ea3288b56e5d..cf742761afa8f9143c67355e23963e366ee4f3c9 100644 --- a/include/mtx/responses/empty.hpp +++ b/include/mtx/responses/empty.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include "mtx/identifiers.hpp" diff --git a/include/mtx/responses/groups.hpp b/include/mtx/responses/groups.hpp index 7872e274ec3b244d53602d868590fcd43fdcdc4c..b7012ac0cb4c1ed6cd456f8eb39ab0502f77df61 100644 --- a/include/mtx/responses/groups.hpp +++ b/include/mtx/responses/groups.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif namespace mtx { namespace responses { diff --git a/include/mtx/responses/login.hpp b/include/mtx/responses/login.hpp index 5b973c249b8573b212cc46ef57d4866bb563dd86..e38f30e9e81761724ee18633816ed159f5570dad 100644 --- a/include/mtx/responses/login.hpp +++ b/include/mtx/responses/login.hpp @@ -3,7 +3,11 @@ #include <optional> #include <string> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include "mtx/identifiers.hpp" #include "mtx/user_interactive.hpp" diff --git a/include/mtx/responses/media.hpp b/include/mtx/responses/media.hpp index 3853923bbf9bc066187f90c9bf0ec4ff31762153..c40e7d0f889497ccbde31454e3543340fdd33f21 100644 --- a/include/mtx/responses/media.hpp +++ b/include/mtx/responses/media.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <string> diff --git a/include/mtx/responses/messages.hpp b/include/mtx/responses/messages.hpp index 3b09ef4c489439b6598bd3aedee974d3a351f1c7..1bf7da48ebe0a9269324304228323fae0435fae1 100644 --- a/include/mtx/responses/messages.hpp +++ b/include/mtx/responses/messages.hpp @@ -2,7 +2,11 @@ #include <string> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include "mtx/events/collections.hpp" diff --git a/include/mtx/responses/notifications.hpp b/include/mtx/responses/notifications.hpp index 7c7804a1b1cc44c38127214f5927bcb8d51e4164..afefcab7cca2222c45291a0f2625062cfd3fb737 100644 --- a/include/mtx/responses/notifications.hpp +++ b/include/mtx/responses/notifications.hpp @@ -1,8 +1,13 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include "mtx/events/collections.hpp" +#include "mtx/pushrules.hpp" namespace mtx { namespace responses { @@ -10,7 +15,7 @@ namespace responses { struct Notification { //! The action to perform when the conditions for this rule are met. - nlohmann::json actions; + std::vector<mtx::pushrules::actions::Action> actions; //! The Event object for the event that triggered the notification. mtx::events::collections::TimelineEvents event; //! Indicates whether the user has sent a read receipt indicating diff --git a/include/mtx/responses/profile.hpp b/include/mtx/responses/profile.hpp index 47c3d1474cf20d066fd38df7ab1f77de656219fb..d1a046b610576bd7aa7584ed9bf3bdc87363631a 100644 --- a/include/mtx/responses/profile.hpp +++ b/include/mtx/responses/profile.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif namespace mtx { namespace responses { diff --git a/include/mtx/responses/register.hpp b/include/mtx/responses/register.hpp index fd0780999e3376d1e532d982da53f82eae38ecc9..4a1c1654674643ed311cc4f02bf28b526bf5f4ea 100644 --- a/include/mtx/responses/register.hpp +++ b/include/mtx/responses/register.hpp @@ -2,7 +2,11 @@ #include <string> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include "mtx/identifiers.hpp" diff --git a/include/mtx/responses/sync.hpp b/include/mtx/responses/sync.hpp index 5af1fbc497ccc6480a894650a78465a1043d6f20..0c1f5fd3671dc48fc2c801cbed8f1c8af30dd4e7 100644 --- a/include/mtx/responses/sync.hpp +++ b/include/mtx/responses/sync.hpp @@ -6,7 +6,11 @@ #include "mtx/events/collections.hpp" +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif namespace mtx { namespace responses { diff --git a/include/mtx/responses/turn_server.hpp b/include/mtx/responses/turn_server.hpp index 8788b95b21b6f24090a5115df3c68271cc6ffe83..c8fe103794fc76997ffac7cc9bc2c950bf7e5c44 100644 --- a/include/mtx/responses/turn_server.hpp +++ b/include/mtx/responses/turn_server.hpp @@ -3,7 +3,11 @@ #include <string> #include <vector> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif namespace mtx::responses { diff --git a/include/mtx/responses/version.hpp b/include/mtx/responses/version.hpp index bc0ab5c0178e477207699f7c633a1023822da5b1..28b44f11bffd3b4676a1ead603ec9788bca5ab8a 100644 --- a/include/mtx/responses/version.hpp +++ b/include/mtx/responses/version.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif namespace mtx { namespace responses { diff --git a/include/mtx/responses/well-known.hpp b/include/mtx/responses/well-known.hpp index 2c53000b1e1fbf9ed2ee209b884a4243fde222bd..98c246aa6f412275ddcbd59f5f20615d02d19277 100644 --- a/include/mtx/responses/well-known.hpp +++ b/include/mtx/responses/well-known.hpp @@ -2,7 +2,11 @@ #include <optional> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif namespace mtx { namespace responses { diff --git a/include/mtx/secret_storage.hpp b/include/mtx/secret_storage.hpp index 2ab388ff357d435bf2cb051d3056f843e3aa72a9..05d0d462e9be450972313229205a52930419dd64 100644 --- a/include/mtx/secret_storage.hpp +++ b/include/mtx/secret_storage.hpp @@ -5,7 +5,11 @@ #include <optional> #include <string> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif namespace mtx { namespace secret_storage { diff --git a/include/mtx/user_interactive.hpp b/include/mtx/user_interactive.hpp index fde1360d0c9e5ec12e84d3f005dc819b57ff4d6f..90c36cc6b5b8061999a33be7f175a86b1f0f9177 100644 --- a/include/mtx/user_interactive.hpp +++ b/include/mtx/user_interactive.hpp @@ -6,7 +6,11 @@ #include <variant> #include <vector> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif namespace mtx { namespace user_interactive { @@ -62,7 +66,7 @@ struct TermsParams void from_json(const nlohmann::json &obj, TermsParams ¶ms); -using Params = std::variant<OAuth2Params, TermsParams, nlohmann::json>; +using Params = std::variant<OAuth2Params, TermsParams, std::string>; struct Unauthorized { diff --git a/include/mtxclient/crypto/client.hpp b/include/mtxclient/crypto/client.hpp index 6d32abad01fe7b0e4debb7cd9cdafb580127b8b6..1476743d3814b23d2e5b807b573ef83556ec3a9d 100644 --- a/include/mtxclient/crypto/client.hpp +++ b/include/mtxclient/crypto/client.hpp @@ -4,7 +4,11 @@ #include <memory> #include <new> +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include <mtx/identifiers.hpp> #include <mtx/requests.hpp> @@ -91,11 +95,6 @@ unpickle(const std::string &pickled, const std::string &key) return object; } -using OlmSessionPtr = std::unique_ptr<OlmSession, OlmDeleter>; -using OutboundGroupSessionPtr = std::unique_ptr<OlmOutboundGroupSession, OlmDeleter>; -using InboundGroupSessionPtr = std::unique_ptr<OlmInboundGroupSession, OlmDeleter>; -using SASPtr = std::unique_ptr<OlmSAS, OlmDeleter>; - struct GroupPlaintext { BinaryBuf data; @@ -125,7 +124,7 @@ public: {} using Base64String = std::string; - using SignedOneTimeKeys = std::map<std::string, json>; + using SignedOneTimeKeys = std::map<std::string, requests::SignedOneTimeKey>; void set_device_id(std::string device_id) { device_id_ = std::move(device_id); } void set_user_id(std::string user_id) { user_id_ = std::move(user_id); } @@ -154,7 +153,8 @@ public: //! Sign one_time_keys and generate the appropriate structure for the /keys/upload request. SignedOneTimeKeys sign_one_time_keys(const OneTimeKeys &keys); //! Generate the json structure for the signed one time key. - json signed_one_time_key_json(const std::string &key, const std::string &signature); + requests::SignedOneTimeKey signed_one_time_key(const std::string &key, + const std::string &signature); //! Marks the current set of one time keys as being published. void mark_keys_as_published() { olm_account_mark_keys_as_published(account_.get()); } diff --git a/include/mtxclient/crypto/objects.hpp b/include/mtxclient/crypto/objects.hpp index 8da33e242d3a568bf6713114cbfef481cca27050..a0fa155a27b8e5ff206dc38d3da3d4ef28d35b42 100644 --- a/include/mtxclient/crypto/objects.hpp +++ b/include/mtxclient/crypto/objects.hpp @@ -184,5 +184,10 @@ create_olm_object() { return std::unique_ptr<typename T::olm_type, OlmDeleter>(T::allocate()); } + +using OlmSessionPtr = std::unique_ptr<OlmSession, OlmDeleter>; +using OutboundGroupSessionPtr = std::unique_ptr<OlmOutboundGroupSession, OlmDeleter>; +using InboundGroupSessionPtr = std::unique_ptr<OlmInboundGroupSession, OlmDeleter>; +using SASPtr = std::unique_ptr<OlmSAS, OlmDeleter>; } } diff --git a/include/mtxclient/crypto/types.hpp b/include/mtxclient/crypto/types.hpp index b78b6f2f8d28ade1358f5fc613c8c06280b97617..455b98dfb4be8db3e375d085808557a6692a47cd 100644 --- a/include/mtxclient/crypto/types.hpp +++ b/include/mtxclient/crypto/types.hpp @@ -1,11 +1,10 @@ #pragma once -#include "mtxclient/utils.hpp" +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> - -STRONG_TYPE(UserId, std::string) -STRONG_TYPE(DeviceId, std::string) -STRONG_TYPE(RoomId, std::string) +#endif namespace mtx { namespace crypto { @@ -70,5 +69,38 @@ to_json(nlohmann::json &obj, const OneTimeKeys &keys); void from_json(const nlohmann::json &obj, OneTimeKeys &keys); +template<class T, class Name> +class strong_type +{ +public: + strong_type() = default; + explicit strong_type(const T &value) + : value_(value) + {} + explicit strong_type(T &&value) + : value_(std::forward<T>(value)) + {} + + operator T &() noexcept { return value_; } + constexpr operator const T &() const noexcept { return value_; } + + T &get() { return value_; } + T const &get() const { return value_; } + +private: + T value_; +}; + +// Macro for concisely defining a strong type +#define STRONG_TYPE(type_name, value_type) \ + struct type_name : mtx::crypto::strong_type<value_type, type_name> \ + { \ + using strong_type::strong_type; \ + }; + } // namespace crypto } // namespace mtx + +STRONG_TYPE(UserId, std::string) +STRONG_TYPE(DeviceId, std::string) +STRONG_TYPE(RoomId, std::string) diff --git a/include/mtxclient/http/client.hpp b/include/mtxclient/http/client.hpp index 0767b92704f8e27f11c08139cb2b4b006f85485b..b82e7c0df74dd30f419e96998683f617389083f7 100644 --- a/include/mtxclient/http/client.hpp +++ b/include/mtxclient/http/client.hpp @@ -1,6 +1,10 @@ #pragma once +#if __has_include(<nlohmann/json_fwd.hpp>) +#include <nlohmann/json_fwd.hpp> +#else #include <nlohmann/json.hpp> +#endif #include "mtx/errors.hpp" // for Error #include "mtx/events.hpp" // for EventType, to_string, json @@ -46,6 +50,7 @@ struct ClaimKeys; struct ContentURI; struct CreateRoom; struct EventId; +struct RoomId; struct FilterId; struct GroupId; struct GroupProfile; @@ -312,9 +317,9 @@ public: void create_room(const mtx::requests::CreateRoom &room_options, Callback<mtx::responses::CreateRoom> cb); //! Join a room by an alias or a room_id. - void join_room(const std::string &room, Callback<nlohmann::json> cb); + void join_room(const std::string &room, Callback<mtx::responses::RoomId> cb); //! Leave a room by its room_id. - void leave_room(const std::string &room_id, Callback<nlohmann::json> cb); + void leave_room(const std::string &room_id, Callback<mtx::responses::Empty> cb); //! Invite a user to a room. void invite_user(const std::string &room_id, const std::string &user_id, @@ -439,18 +444,7 @@ public: void send_to_device( const std::string &txid, const std::map<mtx::identifiers::User, std::map<std::string, EventContent>> &messages, - ErrCallback callback) - { - constexpr auto event_type = mtx::events::to_device_content_to_type<EventContent>; - static_assert(event_type != mtx::events::EventType::Unsupported); - - json j; - for (const auto &[user, deviceToMessage] : messages) - for (const auto &[deviceid, message] : deviceToMessage) - j["messages"][user.to_string()][deviceid] = message; - - send_to_device(mtx::events::to_string(event_type), txid, j, callback); - } + ErrCallback callback); // // Group related endpoints. @@ -598,119 +592,6 @@ private: } } -template<class Request, class Response> -void -mtx::http::Client::post(const std::string &endpoint, - const Request &req, - Callback<Response> callback, - bool requires_auth, - const std::string &content_type) -{ - post( - endpoint, - client::utils::serialize(req), - prepare_callback<Response>( - [callback](const Response &res, HeaderFields, RequestErr err) { callback(res, err); }), - requires_auth, - content_type); -} - -// put function for the PUT HTTP requests that send responses -template<class Request, class Response> -void -mtx::http::Client::put(const std::string &endpoint, - const Request &req, - Callback<Response> callback, - bool requires_auth) -{ - put( - endpoint, - client::utils::serialize(req), - prepare_callback<Response>( - [callback](const Response &res, HeaderFields, RequestErr err) { callback(res, err); }), - requires_auth); -} - -// provides PUT functionality for the endpoints which dont respond with a body -template<class Request> -void -mtx::http::Client::put(const std::string &endpoint, - const Request &req, - ErrCallback callback, - bool requires_auth) -{ - mtx::http::Client::put<Request, mtx::responses::Empty>( - endpoint, - req, - [callback](const mtx::responses::Empty, RequestErr err) { callback(err); }, - requires_auth); -} - -template<class Response> -void -mtx::http::Client::get(const std::string &endpoint, - HeadersCallback<Response> callback, - bool requires_auth, - const std::string &endpoint_namespace) -{ - get(endpoint, prepare_callback<Response>(callback), requires_auth, endpoint_namespace); -} - -template<class Response> -mtx::http::TypeErasedCallback -mtx::http::Client::prepare_callback(HeadersCallback<Response> callback) -{ - auto type_erased_cb = [callback](HeaderFields headers, - const std::string &body, - const boost::system::error_code &err_code, - boost::beast::http::status status_code) { - Response response_data; - mtx::http::ClientError client_error; - - if (err_code) { - client_error.error_code = err_code; - return callback(response_data, headers, client_error); - } - - // We only count 2xx status codes as success. - if (static_cast<int>(status_code) < 200 || static_cast<int>(status_code) >= 300) { - client_error.status_code = status_code; - - // Try to parse the response in case we have an endpoint that - // doesn't return an error struct for non 200 requests. - try { - response_data = client::utils::deserialize<Response>(body); - } catch (const nlohmann::json::exception &e) { - } - - // The homeserver should return an error struct. - try { - nlohmann::json json_error = json::parse(body); - mtx::errors::Error matrix_error = json_error; - - client_error.matrix_error = matrix_error; - return callback(response_data, headers, client_error); - } catch (const nlohmann::json::exception &e) { - client_error.parse_error = std::string(e.what()) + ": " + body; - - return callback(response_data, headers, client_error); - } - } - - // If we reach that point we most likely have a valid output from the - // homeserver. - try { - auto res = client::utils::deserialize<Response>(body); - callback(std::move(res), headers, {}); - } catch (const nlohmann::json::exception &e) { - client_error.parse_error = std::string(e.what()) + ": " + body; - callback(response_data, headers, client_error); - } - }; - - return type_erased_cb; -} - template<class Payload> void mtx::http::Client::send_room_message(const std::string &room_id, diff --git a/include/mtxclient/http/client_impl.hpp b/include/mtxclient/http/client_impl.hpp new file mode 100644 index 0000000000000000000000000000000000000000..067877fe998ef3b7d875704f878e9cd0d3d01d09 --- /dev/null +++ b/include/mtxclient/http/client_impl.hpp @@ -0,0 +1,170 @@ +#pragma once + +#include "client.hpp" +#include "mtxclient/utils.hpp" // for random_token, url_encode, des... + +#include <nlohmann/json.hpp> + +namespace mtx { +namespace client { +namespace utils { +template<class T> +inline T +deserialize(const std::string &data) +{ + return nlohmann::json::parse(data); +} + +template<> +inline std::string +deserialize<std::string>(const std::string &data) +{ + return data; +} + +template<class T> +inline std::string +serialize(const T &obj) +{ + return nlohmann::json(obj).dump(); +} + +template<> +inline std::string +serialize<std::string>(const std::string &obj) +{ + return obj; +} +} +} +} +template<class Request, class Response> +void +mtx::http::Client::post(const std::string &endpoint, + const Request &req, + Callback<Response> callback, + bool requires_auth, + const std::string &content_type) +{ + post( + endpoint, + client::utils::serialize(req), + prepare_callback<Response>( + [callback](const Response &res, HeaderFields, RequestErr err) { callback(res, err); }), + requires_auth, + content_type); +} + +// put function for the PUT HTTP requests that send responses +template<class Request, class Response> +void +mtx::http::Client::put(const std::string &endpoint, + const Request &req, + Callback<Response> callback, + bool requires_auth) +{ + put( + endpoint, + client::utils::serialize(req), + prepare_callback<Response>( + [callback](const Response &res, HeaderFields, RequestErr err) { callback(res, err); }), + requires_auth); +} + +// provides PUT functionality for the endpoints which dont respond with a body +template<class Request> +void +mtx::http::Client::put(const std::string &endpoint, + const Request &req, + ErrCallback callback, + bool requires_auth) +{ + mtx::http::Client::put<Request, mtx::responses::Empty>( + endpoint, + req, + [callback](const mtx::responses::Empty, RequestErr err) { callback(err); }, + requires_auth); +} + +template<class Response> +void +mtx::http::Client::get(const std::string &endpoint, + HeadersCallback<Response> callback, + bool requires_auth, + const std::string &endpoint_namespace) +{ + get(endpoint, prepare_callback<Response>(callback), requires_auth, endpoint_namespace); +} + +template<class Response> +mtx::http::TypeErasedCallback +mtx::http::Client::prepare_callback(HeadersCallback<Response> callback) +{ + auto type_erased_cb = [callback](HeaderFields headers, + const std::string &body, + const boost::system::error_code &err_code, + boost::beast::http::status status_code) { + Response response_data; + mtx::http::ClientError client_error; + + if (err_code) { + client_error.error_code = err_code; + return callback(response_data, headers, client_error); + } + + // We only count 2xx status codes as success. + if (static_cast<int>(status_code) < 200 || static_cast<int>(status_code) >= 300) { + client_error.status_code = status_code; + + // Try to parse the response in case we have an endpoint that + // doesn't return an error struct for non 200 requests. + try { + response_data = client::utils::deserialize<Response>(body); + } catch (const nlohmann::json::exception &e) { + } + + // The homeserver should return an error struct. + try { + nlohmann::json json_error = json::parse(body); + mtx::errors::Error matrix_error = json_error; + + client_error.matrix_error = matrix_error; + return callback(response_data, headers, client_error); + } catch (const nlohmann::json::exception &e) { + client_error.parse_error = std::string(e.what()) + ": " + body; + + return callback(response_data, headers, client_error); + } + } + + // If we reach that point we most likely have a valid output from the + // homeserver. + try { + auto res = client::utils::deserialize<Response>(body); + callback(std::move(res), headers, {}); + } catch (const nlohmann::json::exception &e) { + client_error.parse_error = std::string(e.what()) + ": " + body; + callback(response_data, headers, client_error); + } + }; + + return type_erased_cb; +} + +template<typename EventContent> +void +mtx::http::Client::send_to_device( + const std::string &txid, + const std::map<mtx::identifiers::User, std::map<std::string, EventContent>> &messages, + ErrCallback callback) +{ + constexpr auto event_type = mtx::events::to_device_content_to_type<EventContent>; + static_assert(event_type != mtx::events::EventType::Unsupported); + + json j; + for (const auto &[user, deviceToMessage] : messages) + for (const auto &[deviceid, message] : deviceToMessage) + j["messages"][user.to_string()][deviceid] = message; + + send_to_device(mtx::events::to_string(event_type), txid, j, callback); +} diff --git a/include/mtxclient/http/session.hpp b/include/mtxclient/http/session.hpp index b5175b10a35cc28f6bbf77e1dead987302422644..928de06b97d34ee646e9cbe59d8fb842f29470ab 100644 --- a/include/mtxclient/http/session.hpp +++ b/include/mtxclient/http/session.hpp @@ -4,6 +4,8 @@ #include <boost/asio/ssl.hpp> #include <boost/beast.hpp> +#include <nlohmann/json.hpp> + #include "mtxclient/http/errors.hpp" #include "mtxclient/utils.hpp" diff --git a/include/mtxclient/utils.hpp b/include/mtxclient/utils.hpp index 3af32d8a86299f0eb70bd3db20aba765651cb718..ee98310b11f29f8574e1ca70a259d22000e0dc05 100644 --- a/include/mtxclient/utils.hpp +++ b/include/mtxclient/utils.hpp @@ -3,8 +3,7 @@ #include <boost/iostreams/device/array.hpp> #include <iosfwd> #include <map> - -#include <nlohmann/json.hpp> +#include <string> namespace mtx { namespace client { @@ -42,63 +41,6 @@ decompress(const boost::iostreams::array_source &src, const std::string &type) n //! URL-encode the input string. std::string url_encode(const std::string &s) noexcept; - -template<class T> -inline T -deserialize(const std::string &data) -{ - return nlohmann::json::parse(data); -} - -template<> -inline std::string -deserialize<std::string>(const std::string &data) -{ - return data; -} - -template<class T> -inline std::string -serialize(const T &obj) -{ - return nlohmann::json(obj).dump(); -} - -template<> -inline std::string -serialize<std::string>(const std::string &obj) -{ - return obj; -} - -template<class T, class Name> -class strong_type -{ -public: - strong_type() = default; - explicit strong_type(const T &value) - : value_(value) - {} - explicit strong_type(T &&value) - : value_(std::forward<T>(value)) - {} - - operator T &() noexcept { return value_; } - constexpr operator const T &() const noexcept { return value_; } - - T &get() { return value_; } - T const &get() const { return value_; } - -private: - T value_; -}; - -// Macro for concisely defining a strong type -#define STRONG_TYPE(type_name, value_type) \ - struct type_name : mtx::client::utils::strong_type<value_type, type_name> \ - { \ - using strong_type::strong_type; \ - }; } } } diff --git a/lib/crypto/client.cpp b/lib/crypto/client.cpp index efef3e56cf998c8f0c7f491bced2cde44adb7b0c..baed4e35b201abeace1b505923eff3013ee411a1 100644 --- a/lib/crypto/client.cpp +++ b/lib/crypto/client.cpp @@ -1,5 +1,7 @@ #include <iostream> +#include <nlohmann/json.hpp> + #include <openssl/aes.h> #include <openssl/sha.h> @@ -107,11 +109,11 @@ OlmClient::sign_one_time_key(const std::string &key) return sign_message(j.dump()); } -std::map<std::string, json> +std::map<std::string, mtx::requests::SignedOneTimeKey> OlmClient::sign_one_time_keys(const OneTimeKeys &keys) { // Sign & append the one time keys. - std::map<std::string, json> signed_one_time_keys; + std::map<std::string, mtx::requests::SignedOneTimeKey> signed_one_time_keys; for (const auto &elem : keys.curve25519) { const auto key_id = elem.first; const auto one_time_key = elem.second; @@ -119,17 +121,19 @@ OlmClient::sign_one_time_keys(const OneTimeKeys &keys) auto sig = sign_one_time_key(one_time_key); signed_one_time_keys["signed_curve25519:" + key_id] = - signed_one_time_key_json(one_time_key, sig); + signed_one_time_key(one_time_key, sig); } return signed_one_time_keys; } -json -OlmClient::signed_one_time_key_json(const std::string &key, const std::string &signature) +mtx::requests::SignedOneTimeKey +OlmClient::signed_one_time_key(const std::string &key, const std::string &signature) { - return json{{"key", key}, - {"signatures", {{user_id_, {{"ed25519:" + device_id_, signature}}}}}}; + mtx::requests::SignedOneTimeKey sign{}; + sign.key = key; + sign.signatures = {{user_id_, {{"ed25519:" + device_id_, signature}}}}; + return sign; } mtx::requests::UploadKeys @@ -159,7 +163,9 @@ OlmClient::create_upload_keys_request(const mtx::crypto::OneTimeKeys &one_time_k return req; // Sign & append the one time keys. - req.one_time_keys = sign_one_time_keys(one_time_keys); + auto temp = sign_one_time_keys(one_time_keys); + for (const auto &[key_id, key] : temp) + req.one_time_keys[key_id] = key; return req; } @@ -639,8 +645,6 @@ mtx::crypto::verify_identity_signature(const DeviceKeys &device_keys, const DeviceId &device_id, const UserId &user_id) { - using namespace client::utils; - try { const auto sign_key_id = "ed25519:" + device_id.get(); const auto signing_key = device_keys.keys.at(sign_key_id); @@ -665,8 +669,6 @@ mtx::crypto::ed25519_verify_signature(std::string signing_key, nlohmann::json obj, std::string signature) { - using namespace client::utils; - try { if (signature.empty()) return false; diff --git a/lib/crypto/types.cpp b/lib/crypto/types.cpp index 3543b5e6964ae63eb1aed550ac1cbe975b2e328e..7e324d0c1b9eb06e0f78bd86446c22d137ea6a38 100644 --- a/lib/crypto/types.cpp +++ b/lib/crypto/types.cpp @@ -1,5 +1,7 @@ #include "mtxclient/crypto/types.hpp" +#include <nlohmann/json.hpp> + namespace mtx { namespace crypto { diff --git a/lib/crypto/utils.cpp b/lib/crypto/utils.cpp index 1c211c8f56dbc47f0d35daf7aad8d31dbd7d803b..0913c7732776be78d8cee3677b4c56c0100756e0 100644 --- a/lib/crypto/utils.cpp +++ b/lib/crypto/utils.cpp @@ -1,5 +1,7 @@ #include "mtxclient/crypto/utils.hpp" +#include <nlohmann/json.hpp> + #include <openssl/aes.h> #include <openssl/evp.h> #include <openssl/hmac.h> diff --git a/lib/http/client.cpp b/lib/http/client.cpp index 8e8d0ff52fdd1a725801a0a0eb23d08e1fc410bf..d3f29975aba97e6f03a392c44dd3d955bb25562b 100644 --- a/lib/http/client.cpp +++ b/lib/http/client.cpp @@ -1,17 +1,18 @@ #include "mtxclient/http/client.hpp" +#include "mtxclient/http/client_impl.hpp" #include <mutex> #include <thread> +#include <nlohmann/json.hpp> + #include <boost/algorithm/string.hpp> -#include <boost/bind.hpp> #include <boost/utility/typed_in_place_factory.hpp> -#include <boost/asio.hpp> -#include <boost/asio/ssl.hpp> -#include <boost/beast.hpp> +#include <boost/asio/ssl/context.hpp> +#include <boost/beast/http/message.hpp> #include <boost/iostreams/stream.hpp> -#include <boost/signals2.hpp> +#include <boost/signals2/signal.hpp> #include <boost/signals2/signal_type.hpp> #include <boost/thread/thread.hpp> @@ -45,7 +46,7 @@ Client::Client(const std::string &server, uint16_t port) , p{new ClientPrivate} { using namespace boost::asio; - const auto threads_num = std::max(1U, std::thread::hardware_concurrency()); + const auto threads_num = std::min(8U, std::max(1U, std::thread::hardware_concurrency())); for (unsigned int i = 0; i < threads_num; ++i) p->thread_group_.add_thread(new boost::thread([this]() { p->ios_.run(); })); @@ -599,19 +600,19 @@ Client::create_room(const mtx::requests::CreateRoom &room_options, } void -Client::join_room(const std::string &room, Callback<nlohmann::json> callback) +Client::join_room(const std::string &room, Callback<mtx::responses::RoomId> callback) { auto api_path = "/client/r0/join/" + mtx::client::utils::url_encode(room); - post<std::string, nlohmann::json>(api_path, "{}", callback); + post<std::string, mtx::responses::RoomId>(api_path, "{}", callback); } void -Client::leave_room(const std::string &room_id, Callback<nlohmann::json> callback) +Client::leave_room(const std::string &room_id, Callback<mtx::responses::Empty> callback) { auto api_path = "/client/r0/rooms/" + mtx::client::utils::url_encode(room_id) + "/leave"; - post<std::string, nlohmann::json>(api_path, "{}", callback); + post<std::string, mtx::responses::Empty>(api_path, "{}", callback); } void @@ -1171,3 +1172,79 @@ Client::get_turn_server(Callback<mtx::responses::TurnServer> cb) HeaderFields, RequestErr err) { cb(res, err); }); } + +// Template instantiations for the various send functions + +#define MTXCLIENT_SEND_STATE_EVENT(Content) \ + template void mtx::http::Client::send_state_event<mtx::events::state::Content>( \ + const std::string &, \ + const std::string &state_key, \ + const mtx::events::state::Content &, \ + Callback<mtx::responses::EventId> cb); + +MTXCLIENT_SEND_STATE_EVENT(Aliases) +MTXCLIENT_SEND_STATE_EVENT(Avatar) +MTXCLIENT_SEND_STATE_EVENT(CanonicalAlias) +MTXCLIENT_SEND_STATE_EVENT(Create) +MTXCLIENT_SEND_STATE_EVENT(Encryption) +MTXCLIENT_SEND_STATE_EVENT(GuestAccess) +MTXCLIENT_SEND_STATE_EVENT(HistoryVisibility) +MTXCLIENT_SEND_STATE_EVENT(JoinRules) +MTXCLIENT_SEND_STATE_EVENT(Member) +MTXCLIENT_SEND_STATE_EVENT(Name) +MTXCLIENT_SEND_STATE_EVENT(PinnedEvents) +MTXCLIENT_SEND_STATE_EVENT(PowerLevels) +MTXCLIENT_SEND_STATE_EVENT(Tombstone) +MTXCLIENT_SEND_STATE_EVENT(Topic) + +#define MTXCLIENT_SEND_ROOM_MESSAGE(Content) \ + template void mtx::http::Client::send_room_message<Content>( \ + const std::string &, \ + const std::string &, \ + const Content &, \ + Callback<mtx::responses::EventId> cb); \ + template void mtx::http::Client::send_room_message<Content>( \ + const std::string &, const Content &, Callback<mtx::responses::EventId> cb); + +MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Encrypted) +MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::StickerImage) +MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Reaction) +MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Audio) +MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Emote) +MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::File) +MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Image) +MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Notice) +MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Text) +MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Video) +// MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationRequest) +// MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationStart) +// MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationReady) +// MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationDone) +// MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationAccept) +// MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationCancel) +// MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationKey) +// MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::KeyVerificationMac) +MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::CallInvite) +MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::CallCandidates) +MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::CallAnswer) +MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::CallHangUp) + +#define MTXCLIENT_SEND_TO_DEVICE(Content) \ + template void mtx::http::Client::send_to_device<Content>( \ + const std::string &txid, \ + const std::map<mtx::identifiers::User, std::map<std::string, Content>> &messages, \ + ErrCallback callback); + +MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::RoomKey) +MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::ForwardedRoomKey) +MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyRequest) +MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::OlmEncrypted) +MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::Encrypted) +MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationRequest) +MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationStart) +MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationReady) +MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationDone) +MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationAccept) +MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationCancel) +MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationKey) +MTXCLIENT_SEND_TO_DEVICE(mtx::events::msg::KeyVerificationMac) diff --git a/lib/structs/errors.cpp b/lib/structs/errors.cpp index 0fa246ca9e494f3a6127404e4ad0e6d8fc24efb5..b9ac9dcd74297a9e632474dacdd3244c8dfc91eb 100644 --- a/lib/structs/errors.cpp +++ b/lib/structs/errors.cpp @@ -91,6 +91,13 @@ from_string(const std::string &code) return ErrorCode::M_UNRECOGNIZED; } +void +from_json(const nlohmann::json &obj, LightweightError &error) +{ + error.errcode = from_string(obj.value("errcode", "")); + error.error = obj.value("error", ""); +} + void from_json(const nlohmann::json &obj, Error &error) { diff --git a/lib/structs/events.cpp b/lib/structs/events.cpp index 21fefbaf4233556fdc0a72e9492a69bb567fd1e5..9be4a2241fe29eb958e2ebdb2969124c7e9358f8 100644 --- a/lib/structs/events.cpp +++ b/lib/structs/events.cpp @@ -1,5 +1,7 @@ #include "mtx/events.hpp" +#include <nlohmann/json.hpp> + using json = nlohmann::json; namespace mtx { diff --git a/lib/structs/events/collections.cpp b/lib/structs/events/collections.cpp index 23eb6e5ca70b6e48029636b48aca1385fcb14cc7..5c942216a5744577c74bdfd18108d807ec791e18 100644 --- a/lib/structs/events/collections.cpp +++ b/lib/structs/events/collections.cpp @@ -1,6 +1,93 @@ #include "mtx/events/collections.hpp" +#include "mtx/events_impl.hpp" #include "mtx/log.hpp" +#include <nlohmann/json.hpp> + +namespace mtx::events { +using namespace mtx::events::collections; + +#define MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(EventType, Content) \ + template void to_json<Content>(nlohmann::json &, const EventType<Content> &); \ + template void from_json<Content>(const nlohmann::json &, EventType<Content> &); + +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StateEvent, states::Aliases) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StateEvent, states::Avatar) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StateEvent, states::CanonicalAlias) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StateEvent, states::Create) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StateEvent, states::Encryption) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StateEvent, states::GuestAccess) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StateEvent, states::HistoryVisibility) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StateEvent, states::JoinRules) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StateEvent, states::Member) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StateEvent, states::Name) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StateEvent, states::PinnedEvents) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StateEvent, states::PowerLevels) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StateEvent, states::Tombstone) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StateEvent, states::Topic) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StateEvent, msgs::Redacted) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::EncryptedEvent, msgs::Encrypted) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::EncryptedEvent, msgs::OlmEncrypted) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::StickerImage) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::Reaction) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::Redacted) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::Audio) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::Emote) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::File) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::Image) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::Notice) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::Text) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::Video) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::KeyVerificationRequest) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::KeyVerificationStart) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::KeyVerificationReady) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::KeyVerificationDone) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::KeyVerificationAccept) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::KeyVerificationCancel) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::KeyVerificationKey) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::KeyVerificationMac) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::CallInvite) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::CallCandidates) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::CallAnswer) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, msgs::CallHangUp) + +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StrippedEvent, states::Aliases) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StrippedEvent, states::Avatar) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StrippedEvent, states::CanonicalAlias) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StrippedEvent, states::Create) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StrippedEvent, states::Encryption) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StrippedEvent, states::GuestAccess) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StrippedEvent, states::HistoryVisibility) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StrippedEvent, states::JoinRules) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StrippedEvent, states::Member) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StrippedEvent, states::Name) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StrippedEvent, states::PinnedEvents) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StrippedEvent, states::PowerLevels) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StrippedEvent, states::Tombstone) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::StrippedEvent, states::Topic) + +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::DeviceEvent, msgs::Encrypted) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::DeviceEvent, msgs::OlmEncrypted) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::DeviceEvent, msgs::KeyVerificationRequest) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::DeviceEvent, msgs::KeyVerificationStart) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::DeviceEvent, msgs::KeyVerificationReady) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::DeviceEvent, msgs::KeyVerificationDone) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::DeviceEvent, msgs::KeyVerificationAccept) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::DeviceEvent, msgs::KeyVerificationCancel) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::DeviceEvent, msgs::KeyVerificationKey) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::DeviceEvent, msgs::KeyVerificationMac) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::DeviceEvent, msgs::RoomKey) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::DeviceEvent, msgs::ForwardedRoomKey) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::DeviceEvent, msgs::KeyRequest) + +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::Event, account_data::Tags) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::Event, pushrules::GlobalRuleset) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::Event, account_data::nheko_extensions::HiddenEvents) +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::Event, presence::Presence) + +MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RedactionEvent, msg::Redaction) +} + namespace mtx::events::collections { void from_json(const json &obj, TimelineEvent &e) diff --git a/lib/structs/events/encrypted.cpp b/lib/structs/events/encrypted.cpp index 964d36429598b3f7ddbbafb146f0318ffe12309b..ade1abd6cfc7b804d63a781b9ac5fd143777b204 100644 --- a/lib/structs/events/encrypted.cpp +++ b/lib/structs/events/encrypted.cpp @@ -1,5 +1,7 @@ #include <string> +#include <nlohmann/json.hpp> + #include "mtx/events/encrypted.hpp" static constexpr auto OLM_ALGO = "m.olm.v1.curve25519-aes-sha2"; diff --git a/lib/structs/events/nheko_extensions/hidden_events.cpp b/lib/structs/events/nheko_extensions/hidden_events.cpp index 7f40629ba90601d1bdb35ce7f057ea5a0784fb0d..03cb68cee46ac24978c833a3bf1e5852fa94c38c 100644 --- a/lib/structs/events/nheko_extensions/hidden_events.cpp +++ b/lib/structs/events/nheko_extensions/hidden_events.cpp @@ -1,5 +1,7 @@ #include "mtx/events/nheko_extensions/hidden_events.hpp" +#include <nlohmann/json.hpp> + namespace mtx { namespace events { namespace account_data { diff --git a/lib/structs/requests.cpp b/lib/structs/requests.cpp index ebeda73d151d0925f508581298a5f6ae398d5183..c36ee42b3bb14442819a219b349707ba37168bf3 100644 --- a/lib/structs/requests.cpp +++ b/lib/structs/requests.cpp @@ -2,6 +2,7 @@ #include "mtx/events/collections.hpp" #include "mtx/events/encrypted.hpp" #include <iostream> +#include <nlohmann/json.hpp> using json = nlohmann::json; using namespace mtx::events::collections; @@ -110,6 +111,13 @@ to_json(json &obj, const TypingNotification &request) obj["timeout"] = request.timeout; } +void +to_json(json &obj, const SignedOneTimeKey &request) +{ + obj["key"] = request.key; + obj["signatures"] = request.signatures; +} + void to_json(json &obj, const UploadKeys &request) { @@ -118,8 +126,17 @@ to_json(json &obj, const UploadKeys &request) if (!request.device_keys.user_id.empty()) obj["device_keys"] = request.device_keys; - if (!request.one_time_keys.empty()) - obj["one_time_keys"] = request.one_time_keys; + for (const auto &[key_id, key] : request.one_time_keys) { + obj["one_time_keys"][key_id] = + std::visit([](const auto &e) { return json(e); }, key); + } +} + +void +to_json(json &obj, const ClaimKeys &request) +{ + obj["timeout"] = request.timeout; + obj["one_time_keys"] = request.one_time_keys; } void diff --git a/lib/structs/responses/common.cpp b/lib/structs/responses/common.cpp index 1b7017ad9b06399bc7c74e809bed81061b3b96c8..23e9790d64451d231eef99e17ea2dda388584aa4 100644 --- a/lib/structs/responses/common.cpp +++ b/lib/structs/responses/common.cpp @@ -1,5 +1,7 @@ #include "mtx/responses/common.hpp" +#include <nlohmann/json.hpp> + #include "mtx/events.hpp" #include "mtx/events/aliases.hpp" #include "mtx/events/avatar.hpp" @@ -33,6 +35,12 @@ from_json(const nlohmann::json &obj, GroupId &response) response.group_id = obj.at("group_id"); } +void +from_json(const nlohmann::json &obj, RoomId &response) +{ + response.room_id = obj.at("room_id"); +} + void from_json(const nlohmann::json &obj, EventId &response) { @@ -48,7 +56,7 @@ from_json(const nlohmann::json &obj, FilterId &response) namespace utils { void -log_error(json::exception &err, const json &event) +log_error(std::exception &err, const json &event) { std::cout << err.what() << std::endl; std::cout << event.dump(2) << std::endl; diff --git a/lib/structs/responses/crypto.cpp b/lib/structs/responses/crypto.cpp index 067aa6be868e2e8d09f1c1191770502ee75c0bd6..9cd1475191b147f8c86d07f3602c92d405a409e8 100644 --- a/lib/structs/responses/crypto.cpp +++ b/lib/structs/responses/crypto.cpp @@ -117,7 +117,7 @@ void from_json(const nlohmann::json &obj, BackupVersion &response) { response.algorithm = obj.at("algorithm"); - response.auth_data = obj.at("auth_data"); + response.auth_data = obj.at("auth_data").dump(); response.count = obj.at("count"); response.etag = obj.at("etag").dump(); // workaround, since synapse 1.15.1 and older sends this as integer @@ -127,7 +127,7 @@ void to_json(nlohmann::json &obj, const BackupVersion &response) { obj["algorithm"] = response.algorithm; - obj["auth_data"] = response.auth_data; + obj["auth_data"] = nlohmann::json::parse(response.auth_data); obj["count"] = response.count; obj["etag"] = response.etag; obj["version"] = response.version; diff --git a/lib/structs/responses/empty.cpp b/lib/structs/responses/empty.cpp index c7bb3ff5a370b012ac343c79a272897f6b0a5ce3..0508dc8b397e7c7247e53531bc69c473c74c5d4b 100644 --- a/lib/structs/responses/empty.cpp +++ b/lib/structs/responses/empty.cpp @@ -1,13 +1,11 @@ #include "mtx/responses/empty.hpp" -using json = nlohmann::json; - namespace mtx { namespace responses { // Provides a deserialization function to use when empty responses are returned from the server void -from_json(const json &, Empty &) +from_json(const nlohmann::json &, Empty &) {} } } diff --git a/lib/structs/responses/messages.cpp b/lib/structs/responses/messages.cpp index a116f2327de2cd93927a3027f2a3f500feb9ce3b..3f6a464bd7304c9679a3195c3031114351589df7 100644 --- a/lib/structs/responses/messages.cpp +++ b/lib/structs/responses/messages.cpp @@ -1,6 +1,8 @@ #include "mtx/responses/messages.hpp" #include "mtx/responses/common.hpp" +#include <nlohmann/json.hpp> + using json = nlohmann::json; namespace mtx { diff --git a/lib/structs/responses/notifications.cpp b/lib/structs/responses/notifications.cpp index a692c85a17ca0735cd1834489cd21c74e172b15a..ec13c00fde0b5d6b29e9fc6996460606ff45c675 100644 --- a/lib/structs/responses/notifications.cpp +++ b/lib/structs/responses/notifications.cpp @@ -1,6 +1,8 @@ #include "mtx/responses/notifications.hpp" #include "mtx/responses/common.hpp" +#include <nlohmann/json.hpp> + using json = nlohmann::json; namespace mtx { @@ -9,7 +11,7 @@ namespace responses { void from_json(const json &obj, Notification &res) { - res.actions = obj.at("actions"); + res.actions = obj.at("actions").get<decltype(res.actions)>(); res.read = obj.at("read"); res.room_id = obj.at("room_id"); res.ts = obj.at("ts"); diff --git a/lib/structs/responses/sync.cpp b/lib/structs/responses/sync.cpp index 66d0fb04964c38031895f5bd0464b3298b10222b..8ba836a4942eea485b65b893520cfedeabc17c41 100644 --- a/lib/structs/responses/sync.cpp +++ b/lib/structs/responses/sync.cpp @@ -3,6 +3,8 @@ #include "mtx/log.hpp" #include "mtx/responses/common.hpp" +#include <nlohmann/json.hpp> + #include <variant> using json = nlohmann::json; diff --git a/lib/structs/user_interactive.cpp b/lib/structs/user_interactive.cpp index 93ccc93db9358d3467b970f0542b33b064fe37c1..af6861065616db90e981166f63842a8a5edd8b2d 100644 --- a/lib/structs/user_interactive.cpp +++ b/lib/structs/user_interactive.cpp @@ -1,5 +1,7 @@ #include "mtx/user_interactive.hpp" +#include <nlohmann/json.hpp> + namespace mtx::user_interactive { void from_json(const nlohmann::json &obj, OAuth2Params ¶ms) @@ -50,7 +52,7 @@ from_json(const nlohmann::json &obj, Unauthorized &u) else if (e.key() == auth_types::oauth2) u.params.emplace(e.key(), e.value().get<OAuth2Params>()); else - u.params.emplace(e.key(), e.value()); + u.params.emplace(e.key(), e.value().dump()); } } } diff --git a/tests/client_api.cpp b/tests/client_api.cpp index 4913952c41760d51fea4ac087f41aacd30fb98c3..1d4dab26ceee7464d6398b7540502eb8ef444876 100644 --- a/tests/client_api.cpp +++ b/tests/client_api.cpp @@ -5,6 +5,8 @@ #include <gtest/gtest.h> +#include <nlohmann/json.hpp> + #include "mtx/events/collections.hpp" #include "mtx/events/encrypted.hpp" #include "mtx/requests.hpp" @@ -444,11 +446,13 @@ TEST(ClientAPI, CreateRoomInvites) check_error(err); auto room_id = res.room_id.to_string(); - bob->join_room(room_id, - [](const nlohmann::json &, RequestErr err) { check_error(err); }); + bob->join_room(room_id, [](const mtx::responses::RoomId &, RequestErr err) { + check_error(err); + }); - carl->join_room(room_id, - [](const nlohmann::json &, RequestErr err) { check_error(err); }); + carl->join_room(room_id, [](const mtx::responses::RoomId &, RequestErr err) { + check_error(err); + }); }); alice->close(); @@ -486,20 +490,23 @@ TEST(ClientAPI, JoinRoom) check_error(err); auto room_id = res.room_id.to_string(); - bob->join_room(room_id, - [](const nlohmann::json &, RequestErr err) { check_error(err); }); + bob->join_room(room_id, [](const mtx::responses::RoomId &, RequestErr err) { + check_error(err); + }); using namespace mtx::identifiers; - bob->join_room( - "!random_room_id:localhost", [](const nlohmann::json &, RequestErr err) { - ASSERT_TRUE(err); - EXPECT_EQ(mtx::errors::to_string(err->matrix_error.errcode), - "M_UNKNOWN"); - }); + bob->join_room("!random_room_id:localhost", + [](const mtx::responses::RoomId &, RequestErr err) { + ASSERT_TRUE(err); + EXPECT_EQ( + mtx::errors::to_string(err->matrix_error.errcode), + "M_UNKNOWN"); + }); // Join the room using an alias. - bob->join_room("#" + alias + ":localhost", - [](const nlohmann::json &, RequestErr err) { check_error(err); }); + bob->join_room( + "#" + alias + ":localhost", + [](const mtx::responses::RoomId &, RequestErr err) { check_error(err); }); }); alice->close(); @@ -531,18 +538,18 @@ TEST(ClientAPI, LeaveRoom) auto room_id = res.room_id; bob->join_room(res.room_id.to_string(), - [room_id, bob](const nlohmann::json &, RequestErr err) { + [room_id, bob](const mtx::responses::RoomId &, RequestErr err) { check_error(err); bob->leave_room(room_id.to_string(), - [](const nlohmann::json &, RequestErr err) { + [](mtx::responses::Empty, RequestErr err) { check_error(err); }); }); }); // Trying to leave a non-existent room should fail. - bob->leave_room("!random_room_id:localhost", [](const nlohmann::json &, RequestErr err) { + bob->leave_room("!random_room_id:localhost", [](mtx::responses::Empty, RequestErr err) { ASSERT_TRUE(err); EXPECT_EQ(mtx::errors::to_string(err->matrix_error.errcode), "M_UNKNOWN"); EXPECT_EQ(err->matrix_error.error, "Not a known room"); @@ -583,7 +590,8 @@ TEST(ClientAPI, InviteRoom) check_error(err); bob->join_room( - room_id, [](const nlohmann::json &, RequestErr err) { + room_id, + [](const mtx::responses::RoomId &, RequestErr err) { check_error(err); }); }); @@ -625,7 +633,8 @@ TEST(ClientAPI, KickRoom) check_error(err); bob->join_room( - room_id, [alice, room_id](const nlohmann::json &, RequestErr err) { + room_id, + [alice, room_id](const mtx::responses::RoomId &, RequestErr err) { check_error(err); alice->kick_user(room_id, @@ -672,7 +681,8 @@ TEST(ClientAPI, BanRoom) check_error(err); bob->join_room( - room_id, [alice, room_id](const nlohmann::json &, RequestErr err) { + room_id, + [alice, room_id](const mtx::responses::RoomId &, RequestErr err) { check_error(err); alice->ban_user( @@ -912,7 +922,7 @@ TEST(ClientAPI, PresenceOverSync) auto room_id = res.room_id.to_string(); bob->join_room( - room_id, [alice, bob, room_id](const nlohmann::json &, RequestErr err) { + room_id, [alice, bob, room_id](const mtx::responses::RoomId &, RequestErr err) { check_error(err); alice->put_presence_status( mtx::presence::unavailable, @@ -984,7 +994,7 @@ TEST(ClientAPI, SendMessages) auto room_id = res.room_id.to_string(); bob->join_room( - room_id, [alice, bob, room_id](const nlohmann::json &, RequestErr err) { + room_id, [alice, bob, room_id](const mtx::responses::RoomId &, RequestErr err) { check_error(err); // Flag to indicate when those messages would be ready to be read by diff --git a/tests/e2ee.cpp b/tests/e2ee.cpp index 9ca3009f4d80b086a573bef657b9a49dcbf13318..f2d08d2fb759c10030dae4ce2681008cae10c9b9 100644 --- a/tests/e2ee.cpp +++ b/tests/e2ee.cpp @@ -4,6 +4,8 @@ #include <gtest/gtest.h> +#include <nlohmann/json.hpp> + #include "mtxclient/crypto/client.hpp" #include "mtxclient/crypto/types.hpp" #include "mtxclient/http/client.hpp" @@ -116,18 +118,12 @@ TEST(Encryption, UploadOneTimeKeys) auto nkeys = olm_account->generate_one_time_keys(5); EXPECT_EQ(nkeys, 5); - json otks = olm_account->one_time_keys(); + auto otks = olm_account->one_time_keys(); mtx::requests::UploadKeys req; - // Create the proper structure for uploading. - std::map<std::string, json> unsigned_keys; - - auto obj = otks.at("curve25519"); - for (auto it = obj.begin(); it != obj.end(); ++it) - unsigned_keys["curve25519:" + it.key()] = it.value(); - - req.one_time_keys = unsigned_keys; + for (auto [key_id, key] : otks.curve25519) + req.one_time_keys["curve25519:" + key_id] = key; alice->upload_keys(req, [](const mtx::responses::UploadKeys &res, RequestErr err) { check_error(err); @@ -160,7 +156,8 @@ TEST(Encryption, UploadSignedOneTimeKeys) auto one_time_keys = olm_account->one_time_keys(); mtx::requests::UploadKeys req; - req.one_time_keys = olm_account->sign_one_time_keys(one_time_keys); + for (const auto &[key_id, key] : olm_account->sign_one_time_keys(one_time_keys)) + req.one_time_keys[key_id] = key; alice->upload_keys(req, [nkeys](const mtx::responses::UploadKeys &res, RequestErr err) { check_error(err); @@ -570,7 +567,7 @@ TEST(Encryption, EnableEncryption) }); carl->join_room(res.room_id.to_string(), - [&responses](const nlohmann::json &, RequestErr err) { + [&responses](const mtx::responses::RoomId &, RequestErr err) { check_error(err); responses += 1; }); @@ -849,7 +846,7 @@ TEST(Encryption, OlmRoomKeyEncryption) // Alice create m.room.key request json payload = - json{{"content", {"secret", SECRET_TEXT}}, {"type", "im.nheko.custom_test_event"}}; + json{{"content", {{"secret", SECRET_TEXT}}}, {"type", "im.nheko.custom_test_event"}}; // Alice creates an outbound session. auto out_session = alice_olm->create_outbound_session(bob_curve25519, bob_otk); diff --git a/tests/requests.cpp b/tests/requests.cpp index ad4b181e64dba2342ef3f401d33adde727b545f8..b1e637431fe04cffdd401c8a971450d3676c6eb0 100644 --- a/tests/requests.cpp +++ b/tests/requests.cpp @@ -83,20 +83,17 @@ TEST(Requests, UploadKeys) "EjzaoycHcjq9lfQX0uWsqxl2giMIiSPR8a4d291W1ihKJL/" "a+myXS367WT6NAIcBA\"}},\"user_id\":\"@alice:example.com\"}}"); - json k1 = {{"key", "zKbLg+NrIjpnagy+pIY6uPL4ZwEG2v+8F9lmgsnlZzs"}, - {"signatures", - {{"@alice:example.com", - {{"ed25519:JLAFKJWSCS", - "IQeCEPb9HFk217cU9kw9EOiusC6kMIkoIRnbnfOh5Oc63S1ghgyjShBGpu34blQomoalCyXWyh" - "aaT3MrLZYQ" - "AA"}}}}}}; - - json k2 = {{"key", "j3fR3HemM16M7CWhoI4Sk5ZsdmdfQHsKL1xuSft6MSw"}, - {"signatures", - {{"@alice:example.com", - {{"ed25519:JLAFKJWSCS", - "FLWxXqGbwrb8SM3Y795eB6OA8bwBcoMZFXBqnTn58AYWZSqiD45tlBVcDa2L7RwdKXebW/" - "VzDlnfVJ+9jok1Bw"}}}}}}; + mtx::requests::SignedOneTimeKey k1; + k1.key = "zKbLg+NrIjpnagy+pIY6uPL4ZwEG2v+8F9lmgsnlZzs"; + k1.signatures = {{"@alice:example.com", + {{"ed25519:JLAFKJWSCS", + "IQeCEPb9HFk217cU9kw9EOiusC6kMIkoIRnbnfOh5Oc63S1ghgyjShBGpu34blQomoalCy" + "XWyhaaT3MrLZYQAA"}}}}; + + mtx::requests::SignedOneTimeKey k2; + k2.key = "j3fR3HemM16M7CWhoI4Sk5ZsdmdfQHsKL1xuSft6MSw"; + k2.signatures["@alice:example.com"]["ed25519:JLAFKJWSCS"] = + "FLWxXqGbwrb8SM3Y795eB6OA8bwBcoMZFXBqnTn58AYWZSqiD45tlBVcDa2L7RwdKXebW/VzDlnfVJ+9jok1Bw"; r3.one_time_keys.emplace("curve25519:AAAAAQ", "/qyvZvwjiTxGdGU0RCguDCLeR+nmsb3FfNG3/Ve4vU8");