diff --git a/matrix/matrix.cc b/matrix/matrix.cc index 71aafe5c2..8ad8336be 100644 --- a/matrix/matrix.cc +++ b/matrix/matrix.cc @@ -59,6 +59,7 @@ ircd::m::module_names "m_noop", "m_breadcrumbs", "m_bridge", + "m_bridge_register", "m_command", "m_control", "m_device", diff --git a/modules/Makefile.am b/modules/Makefile.am index 01bc92f57..8469aaa88 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -81,6 +81,7 @@ m_moduledir = @moduledir@ m_breadcrumbs_la_SOURCES = m_breadcrumbs.cc m_bridge_la_SOURCES = m_bridge.cc +m_bridge_register_la_SOURCES = m_bridge_register.cc m_command_la_SOURCES = m_command.cc m_control_la_SOURCES = m_control.cc m_device_la_SOURCES = m_device.cc @@ -114,6 +115,7 @@ m_room_tombstone_la_SOURCES = m_room_tombstone.cc m_module_LTLIBRARIES = \ m_breadcrumbs.la \ m_bridge.la \ + m_bridge_register.la \ m_command.la \ m_control.la \ m_device.la \ diff --git a/modules/console.cc b/modules/console.cc index cd104158e..57564b51c 100644 --- a/modules/console.cc +++ b/modules/console.cc @@ -17634,6 +17634,30 @@ console_cmd__bridge__protocol(opt &out, const string_view &line) return true; } +bool +console_cmd__bridge__set(opt &out, const string_view &line) +{ + const params param{line, " ", + { + "file" + }}; + + static mods::import set + { + "m_bridge_register", "ircd::m::bridge::set" + }; + + const auto event_id + { + set(param.at("file")) + }; + + out + << "Bridge set. Configuration event: " << event_id + << std::endl; + return true; +} + // // icu // diff --git a/modules/m_bridge_register.cc b/modules/m_bridge_register.cc new file mode 100644 index 000000000..b53bc56b2 --- /dev/null +++ b/modules/m_bridge_register.cc @@ -0,0 +1,131 @@ +// The Construct +// +// Copyright (C) The Construct Developers, Authors & Contributors +// Copyright (C) 2016-2023 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. + +namespace ircd::m::bridge +{ + event::id::buf set(const string_view &file); +} + +ircd::mapi::header +IRCD_MODULE +{ + "Bridges (Application Services) :Registration" +}; + +ircd::m::event::id::buf +IRCD_MODULE_EXPORT_CODE +ircd::m::bridge::set(const string_view &file) +{ + const fs::fd fd + { + file + }; + + std::string content + { + fs::read(fd) + }; + + m::bridge::config config + { + json::object(content) + }; + + const auto update + { + [&content, &config] + { + content = json::strung(config); + config = json::object(content); + } + }; + + const m::user::id::buf user_id + { + at<"sender_localpart"_>(config), origin(my()) + }; + + const m::room::id::buf room_id + { + at<"sender_localpart"_>(config), origin(my()) + }; + + const bool user_exists + { + m::exists(user_id) + }; + + const bool room_exists + { + m::exists(room_id) + }; + + const bool has_as_token + { + !empty(json::get<"as_token"_>(config)) + }; + + const bool has_as_token_prefix + { + startswith(json::get<"as_token"_>(config), "bridge_") + }; + + if(json::get<"id"_>(config) != user_id.localname()) + throw error + { + "sender_localpart '%s' must match id '%s'", + json::get<"sender_localpart"_>(config), + json::get<"id"_>(config), + }; + + if(!user_exists) + m::create(user_id); + + if(!room_exists) + m::create(room_id, user_id); + + if(!is_oper(user_id)) + m::user(user_id).oper(); + + const m::user::tokens tokens + { + user_id + }; + + if(!has_as_token) + { + char buf[2][128]; + strlcpy(buf[0], "bridge_"); + strlcat(buf[0], m::user::tokens::generate(buf[1])); + const string_view token{buf[0]}; + tokens.add(token); + json::get<"as_token"_>(config) = token; + update(); + } + else if(!has_as_token_prefix) + { + char buf[128]; + strlcpy(buf, "bridge_"); + strlcat(buf, json::get<"as_token"_>(config)); + const string_view token{buf}; + tokens.add(token); + json::get<"as_token"_>(config) = token; + update(); + } + else if(!tokens.check(json::get<"as_token"_>(config))) + tokens.add(json::get<"as_token"_>(config)); + + const auto event_id + { + m::send(room_id, user_id, "ircd.bridge", at<"id"_>(config), content) + }; + + return event_id; +}