diff --git a/modules/client/room_keys/keys.cc b/modules/client/room_keys/keys.cc index bfb307d41..26382b445 100644 --- a/modules/client/room_keys/keys.cc +++ b/modules/client/room_keys/keys.cc @@ -13,6 +13,7 @@ namespace ircd::m static resource::response get_room_keys_keys(client &, const resource::request &); extern resource::method room_keys_keys_get; + static void put_room_keys_keys_key(client &, const resource::request &, const room::id &, const string_view &, const event::idx &, const json::object &); static resource::response put_room_keys_keys(client &, const resource::request &); extern resource::method room_keys_keys_put; @@ -79,10 +80,103 @@ ircd::m::resource::response ircd::m::put_room_keys_keys(client &client, const resource::request &request) { + char room_id_buf[room::id::buf::SIZE]; + const string_view &room_id + { + request.parv.size() > 0? + url::decode(room_id_buf, request.parv[0]): + string_view{} + }; + + char session_id_buf[256]; + const string_view &session_id + { + request.parv.size() > 1? + url::decode(session_id_buf, request.parv[1]): + string_view{} + }; + + const event::idx version + { + request.query.at("version") + }; + + if(!room_id && !session_id) + { + const json::object &rooms + { + request["rooms"] + }; + + for(const auto &[room_id, sessions] : rooms) + for(const auto &[session_id, session] : json::object(sessions)) + put_room_keys_keys_key(client, request, room_id, session_id, version, session); + } + else if(!session_id) + { + const json::object &sessions + { + request["sessions"] + }; + + for(const auto &[session_id, session] : sessions) + put_room_keys_keys_key(client, request, room_id, session_id, version, session); + } + else put_room_keys_keys_key(client, request, room_id, session_id, version, request); return resource::response { - client, http::NOT_IMPLEMENTED + client, http::OK + }; +} + +void +ircd::m::put_room_keys_keys_key(client &client, + const resource::request &request, + const room::id &room_id, + const string_view &session_id, + const event::idx &version, + const json::object &content) +{ + const m::user::room user_room + { + request.user_id + }; + + const m::room::type events + { + user_room, "ircd.room_keys.version" + }; + + events.for_each([&version] + (const auto &, const auto &, const event::idx &_event_idx) + { + if(m::redacted(_event_idx)) + return true; + + if(_event_idx != version) + throw http::error + { + "%lu is not the most recent key version", + http::FORBIDDEN, + version + }; + + return false; // false to break after this first hit + }); + + char state_key_buf[event::STATE_KEY_MAX_SIZE]; + const string_view state_key{fmt::sprintf + { + state_key_buf, "%s:%s:%u", + string_view{room_id}, + session_id, + version, + }}; + + const auto event_id + { + send(user_room, request.user_id, "ircd.room_keys.key", state_key, content) }; }