diff --git a/modules/Makefile.am b/modules/Makefile.am index 2a6fc8a45..ff6da3b38 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -263,6 +263,7 @@ federation_federation_make_leave_la_SOURCES = federation/make_leave.cc federation_federation_send_leave_la_SOURCES = federation/send_leave.cc federation_federation_backfill_la_SOURCES = federation/backfill.cc federation_federation_backfill_ids_la_SOURCES = federation/backfill_ids.cc +federation_federation_event_auth_la_SOURCES = federation/event_auth.cc federation_federation_federation_la_SOURCES = federation/federation.cc federation_module_LTLIBRARIES = \ @@ -282,6 +283,7 @@ federation_module_LTLIBRARIES = \ federation/federation_send_leave.la \ federation/federation_backfill.la \ federation/federation_backfill_ids.la \ + federation/federation_event_auth.la \ federation/federation_federation.la \ ### diff --git a/modules/federation/event_auth.cc b/modules/federation/event_auth.cc new file mode 100644 index 000000000..198472223 --- /dev/null +++ b/modules/federation/event_auth.cc @@ -0,0 +1,145 @@ +// 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 event_auth (undocumented)" +}; + +resource +event_auth_resource +{ + "/_matrix/federation/v1/event_auth/", + { + "federation event_auth", + resource::DIRECTORY, + } +}; + +conf::item +event_auth_flush_hiwat +{ + { "name", "ircd.federation.event_auth.flush.hiwat" }, + { "default", 16384L }, +}; + +resource::response +get__event_auth(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 + { + "event_id path parameter required" + }; + + m::event::id::buf event_id + { + url::decode(request.parv[1], event_id) + }; + + const m::event::fetch event + { + event_id + }; + + const m::room room + { + room_id, event_id + }; + + if(!room.visible(request.node_id)) + throw m::ACCESS_DENIED + { + "You are not permitted to view the room at this event" + }; + + const m::room::state state + { + room + }; + + const unique_buffer buf + { + 96_KiB + }; + + resource::response::chunked response + { + client, http::OK + }; + + const auto flush{[&response] + (const const_buffer &buf) + { + response.write(buf); + return buf; + }}; + + json::stack out + { + buf, flush, size_t(event_auth_flush_hiwat) + }; + + json::stack::object top{out}; + json::stack::member auth_chain_m + { + top, "auth_chain" + }; + + json::stack::array auth_chain + { + auth_chain_m + }; + + const auto append{[&auth_chain] + (const m::event &event) + { + if(json::get<"event_id"_>(event)) + auth_chain.append(event); + }}; + + const auto append_with_sender{[&append, &state, &event] + (const m::event &event_) + { + append(event_); + if(json::get<"sender"_>(event_) != json::get<"sender"_>(event)) + state.get(std::nothrow, "m.room.member", json::get<"sender"_>(event_), append); + }}; + + state.get(std::nothrow, "m.room.create", "", append); + state.get(std::nothrow, "m.room.join_rules", "", append); + state.get(std::nothrow, "m.room.power_levels", "", append_with_sender); + state.get(std::nothrow, "m.room.member", json::get<"sender"_>(event), append); + return {}; +} + +resource::method +method_get +{ + event_auth_resource, "GET", get__event_auth, + { + method_get.VERIFY_ORIGIN + } +};