diff --git a/modules/Makefile.am b/modules/Makefile.am index 2eb00b8bb..cf5e33f46 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -243,6 +243,7 @@ federation_federation_version_la_SOURCES = federation/version.cc federation_federation_sender_la_SOURCES = federation/sender.cc federation_federation_query_la_SOURCES = federation/query.cc federation_federation_invite_la_SOURCES = federation/invite.cc +federation_federation_make_join_la_SOURCES = federation/make_join.cc federation_module_LTLIBRARIES = \ federation/federation_send.la \ @@ -253,6 +254,7 @@ federation_module_LTLIBRARIES = \ federation/federation_sender.la \ federation/federation_query.la \ federation/federation_invite.la \ + federation/federation_make_join.la \ ### ############################################################################### diff --git a/modules/federation/make_join.cc b/modules/federation/make_join.cc new file mode 100644 index 000000000..b28b81f63 --- /dev/null +++ b/modules/federation/make_join.cc @@ -0,0 +1,127 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2018 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +using namespace ircd; + +mapi::header +IRCD_MODULE +{ + "Federation :Request a prototype for creating a join event." +}; + +const string_view +make_join_description +{R"( + +Sends a partial event to the remote with enough information for them to +create a join event 'in the blind' for one of their users. + +)"}; + +resource +make_join_resource +{ + "/_matrix/federation/v1/make_join/", + { + make_join_description, + resource::DIRECTORY + } +}; + +resource::response +get__make_join(client &client, + const resource::request &request) +{ + if(request.parv.size() < 1) + throw m::NEED_MORE_PARAMS + { + "room_id path parameter required" + }; + + m::room::id::buf room_id + { + url::decode(request.parv[0], room_id) + }; + + if(request.parv.size() < 2) + throw m::NEED_MORE_PARAMS + { + "user_id path parameter required" + }; + + m::user::id::buf user_id + { + url::decode(request.parv[1], user_id) + }; + + uint64_t depth; + const m::event::id::buf prev_event_id + { + m::head(room_id, depth) + }; + + const m::event::fetch evf + { + prev_event_id, std::nothrow + }; + + const auto &auth_events + { + json::get<"auth_events"_>(evf)? + json::get<"auth_events"_>(evf) : json::array{"[]"} + }; + + const json::value prev[] + { + { string_view{prev_event_id} }, + { json::get<"hashes"_>(evf) } + }; + + const json::value prevs[] + { + { prev, 2 } + }; + + thread_local char bufs[96_KiB]; + mutable_buffer buf{bufs}; + + json::iov content, event, wrapper; + const json::iov::push push[] + { + { event, { "origin", request.origin }}, + { event, { "origin_server_ts", time() }}, + { event, { "room_id", room_id }}, + { event, { "type", "m.room.member" }}, + { event, { "state_key", user_id }}, + { event, { "sender", user_id }}, + { event, { "depth", int64_t(depth) + 1 }}, + { event, { "membership", "join" }}, + { content, { "membership", "join" }}, + { event, { "auth_events", auth_events }}, + { event, { "prev_state", "[]" }}, + { event, { "prev_events", { prevs, 1 } }}, + { event, { "content", stringify(buf, content) }}, + { wrapper, { "event", stringify(buf, event) }}, + }; + + return resource::response + { + client, wrapper + }; +} + +resource::method +method_get +{ + make_join_resource, "GET", get__make_join, + { + method_get.VERIFY_ORIGIN + } +};