From 183e44e0b6929d27fc9222bf06773e46da74b6f6 Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Thu, 26 Sep 2019 12:16:22 -0700 Subject: [PATCH] modules: Distill all API's from modules up to matrix lib. --- include/ircd/m/feds.h | 11 + include/ircd/m/receipt.h | 2 + include/ircd/m/user/events.h | 4 +- include/ircd/m/user/mitsein.h | 4 +- include/ircd/m/user/rooms.h | 4 +- include/ircd/m/user/servers.h | 4 +- matrix/Makefile.am | 59 ++- matrix/breadcrumb_rooms.cc | 75 +++ {modules => matrix}/conf.cc | 22 +- modules/m_create.cc => matrix/create.cc | 6 - matrix/device.cc | 310 ++++++++++++ modules/m_room.cc => matrix/display_name.cc | 11 - .../event_append.cc | 6 - .../event_horizon.cc | 6 - modules/m_events.cc => matrix/events.cc | 6 - modules/m_feds.cc => matrix/feds.cc | 18 +- modules/m_fetch.cc => matrix/fetch.cc | 6 - matrix/ignored_user_list.cc | 91 ++++ .../init_backfill.cc | 8 - modules/m_room_join.cc => matrix/join.cc | 6 - modules/m_keys.cc => matrix/keys.cc | 7 - modules/m_room_leave.cc => matrix/leave.cc | 6 - matrix/matrix.cc | 294 +---------- modules/m_node.cc => matrix/node.cc | 10 - matrix/presence.cc | 105 ++++ modules/m_event_pretty.cc => matrix/pretty.cc | 6 - matrix/receipt.cc | 194 ++++++++ matrix/room.cc | 140 ------ matrix/room_aliases.cc | 465 ++++++++++++++++++ modules/m_room_auth.cc => matrix/room_auth.cc | 6 - .../room_bootstrap.cc | 6 - .../m_room_events.cc => matrix/room_events.cc | 6 - modules/m_room_head.cc => matrix/room_head.cc | 10 - matrix/room_history_visibility.cc | 150 ++++++ matrix/room_server_acl.cc | 332 +++++++++++++ modules/m_rooms.cc => matrix/rooms.cc | 7 +- .../rooms_summary.cc | 6 - modules/m_typing.cc => matrix/typing.cc | 6 - modules/m_user.cc => matrix/user.cc | 12 +- .../user_account_data.cc | 6 - .../m_user_events.cc => matrix/user_events.cc | 12 - .../m_user_filter.cc => matrix/user_filter.cc | 6 - .../user_highlight.cc | 17 +- .../user_mitsein.cc | 12 - .../user_profile.cc | 6 - .../user_register.cc | 6 - .../user_room_account_data.cc | 6 - .../user_room_tags.cc | 6 - .../m_user_rooms.cc => matrix/user_rooms.cc | 12 - modules/m_users.cc => matrix/users.cc | 6 - .../users_servers.cc | 12 - modules/Makefile.am | 151 ++---- modules/m_breadcrumb_rooms.cc | 66 --- modules/m_device.cc | 301 ------------ modules/m_device_list_update.cc | 8 +- modules/m_event.cc | 20 - modules/m_ignored_user_list.cc | 76 --- modules/m_presence.cc | 89 ---- modules/m_receipt.cc | 222 +-------- modules/m_room_aliases.cc | 438 ----------------- modules/m_room_history_visibility.cc | 138 ------ modules/m_room_server_acl.cc | 328 ------------ 62 files changed, 1893 insertions(+), 2478 deletions(-) create mode 100644 matrix/breadcrumb_rooms.cc rename {modules => matrix}/conf.cc (95%) rename modules/m_create.cc => matrix/create.cc (99%) create mode 100644 matrix/device.cc rename modules/m_room.cc => matrix/display_name.cc (92%) rename modules/m_event_append.cc => matrix/event_append.cc (98%) rename modules/m_event_horizon.cc => matrix/event_horizon.cc (95%) rename modules/m_events.cc => matrix/events.cc (99%) rename modules/m_feds.cc => matrix/feds.cc (97%) rename modules/m_fetch.cc => matrix/fetch.cc (99%) create mode 100644 matrix/ignored_user_list.cc rename modules/m_init_backfill.cc => matrix/init_backfill.cc (98%) rename modules/m_room_join.cc => matrix/join.cc (98%) rename modules/m_keys.cc => matrix/keys.cc (99%) rename modules/m_room_leave.cc => matrix/leave.cc (96%) rename modules/m_node.cc => matrix/node.cc (93%) create mode 100644 matrix/presence.cc rename modules/m_event_pretty.cc => matrix/pretty.cc (97%) create mode 100644 matrix/receipt.cc create mode 100644 matrix/room_aliases.cc rename modules/m_room_auth.cc => matrix/room_auth.cc (99%) rename modules/m_room_bootstrap.cc => matrix/room_bootstrap.cc (99%) rename modules/m_room_events.cc => matrix/room_events.cc (99%) rename modules/m_room_head.cc => matrix/room_head.cc (98%) create mode 100644 matrix/room_history_visibility.cc create mode 100644 matrix/room_server_acl.cc rename modules/m_rooms.cc => matrix/rooms.cc (97%) rename modules/m_rooms_summary.cc => matrix/rooms_summary.cc (99%) rename modules/m_typing.cc => matrix/typing.cc (99%) rename modules/m_user.cc => matrix/user.cc (96%) rename modules/m_user_account_data.cc => matrix/user_account_data.cc (97%) rename modules/m_user_events.cc => matrix/user_events.cc (90%) rename modules/m_user_filter.cc => matrix/user_filter.cc (98%) rename modules/m_user_highlight.cc => matrix/user_highlight.cc (98%) rename modules/m_user_mitsein.cc => matrix/user_mitsein.cc (95%) rename modules/m_user_profile.cc => matrix/user_profile.cc (98%) rename modules/m_user_register.cc => matrix/user_register.cc (98%) rename modules/m_user_room_account_data.cc => matrix/user_room_account_data.cc (97%) rename modules/m_user_room_tags.cc => matrix/user_room_tags.cc (98%) rename modules/m_user_rooms.cc => matrix/user_rooms.cc (93%) rename modules/m_users.cc => matrix/users.cc (98%) rename modules/m_user_servers.cc => matrix/users_servers.cc (90%) delete mode 100644 modules/m_event.cc diff --git a/include/ircd/m/feds.h b/include/ircd/m/feds.h index f630821b2..66689caaf 100644 --- a/include/ircd/m/feds.h +++ b/include/ircd/m/feds.h @@ -45,6 +45,7 @@ namespace ircd::m::feds /// the user can distinguish different requests in their options vector. /// struct ircd::m::feds::execute +:boolean { execute(const vector_view &, const closure &); execute(const opts &, const closure &); @@ -142,3 +143,13 @@ struct ircd::m::feds::opts /// typical use case. bool exclude_myself {false}; }; + +inline +ircd::m::feds::execute::execute(const opts &opts, + const closure &closure) +:execute +{ + vector_view(std::addressof(opts), 1), + closure +} +{} diff --git a/include/ircd/m/receipt.h b/include/ircd/m/receipt.h index 2db229b0f..bc4d603f4 100644 --- a/include/ircd/m/receipt.h +++ b/include/ircd/m/receipt.h @@ -32,6 +32,8 @@ namespace ircd::m::receipt // [SET] Indicate that the user has read the event in the room. id::event::buf read(const id::room &, const id::user &, const id::event &, const json::object & = {}); + + extern log::log log; }; struct ircd::m::edu::m_receipt diff --git a/include/ircd/m/user/events.h b/include/ircd/m/user/events.h index ba69e647e..147a85115 100644 --- a/include/ircd/m/user/events.h +++ b/include/ircd/m/user/events.h @@ -24,5 +24,7 @@ struct ircd::m::user::events bool for_each(const closure_bool &) const; size_t count() const; - events(const m::user &user); + events(const m::user &user) + :user{user} + {} }; diff --git a/include/ircd/m/user/mitsein.h b/include/ircd/m/user/mitsein.h index c2058de00..2b560d0ea 100644 --- a/include/ircd/m/user/mitsein.h +++ b/include/ircd/m/user/mitsein.h @@ -32,5 +32,7 @@ struct ircd::m::user::mitsein // Existential convenience (does `user` and `other` share any common room). bool has(const m::user &other, const string_view &membership = {}) const; - mitsein(const m::user &user); + mitsein(const m::user &user) + :user{user} + {} }; diff --git a/include/ircd/m/user/rooms.h b/include/ircd/m/user/rooms.h index 69b2e45b7..90c47e138 100644 --- a/include/ircd/m/user/rooms.h +++ b/include/ircd/m/user/rooms.h @@ -33,5 +33,7 @@ struct ircd::m::user::rooms size_t count(const string_view &membership) const; size_t count() const; - rooms(const m::user &user); + rooms(const m::user &user) + :user_room{user} + {} }; diff --git a/include/ircd/m/user/servers.h b/include/ircd/m/user/servers.h index e8fc13529..4d568d676 100644 --- a/include/ircd/m/user/servers.h +++ b/include/ircd/m/user/servers.h @@ -29,5 +29,7 @@ struct ircd::m::user::servers // Existential convenience (does `user` and `other` share any common room). bool has(const string_view &server, const string_view &membership = {}) const; - servers(const m::user &user); + servers(const m::user &user) + :user{user} + {} }; diff --git a/matrix/Makefile.am b/matrix/Makefile.am index ad6596b3a..f1d953190 100644 --- a/matrix/Makefile.am +++ b/matrix/Makefile.am @@ -26,15 +26,18 @@ AM_CPPFLAGS = \ AM_LDFLAGS = \ -version-info 0:1:0 \ -Wl,--no-undefined-version \ - -Wl,--unresolved-symbols=report-all \ -Wl,--allow-shlib-undefined \ - -Wl,--weak-unresolved-symbols \ + -Wl,--unresolved-symbols=ignore-in-shared-libs \ -Wl,-z,now \ -L$(top_srcdir)/ircd \ $(PLATFORM_LDFLAGS) \ @EXTRA_LDFLAGS@ \ ### +AM_LIBS = \ + -lircd \ + ### + if MINGW AM_LDFLAGS += \ -Wl,--enable-runtime-pseudo-reloc \ @@ -46,10 +49,6 @@ libircd_matrix_LTLIBRARIES = \ libircd_matrix.la \ ### -libircd_matrix_la_LIBADD = \ - -lircd \ - ### - # # Unit list # @@ -58,11 +57,53 @@ libircd_matrix_la_SOURCES =# libircd_matrix_la_SOURCES += name.cc libircd_matrix_la_SOURCES += id.cc libircd_matrix_la_SOURCES += dbs.cc -libircd_matrix_la_SOURCES += room.cc -libircd_matrix_la_SOURCES += fed.cc -libircd_matrix_la_SOURCES += init_bootstrap.cc libircd_matrix_la_SOURCES += matrix.cc libircd_matrix_la_SOURCES += event.cc +libircd_matrix_la_SOURCES += room.cc +libircd_matrix_la_SOURCES += user.cc +libircd_matrix_la_SOURCES += breadcrumb_rooms.cc +libircd_matrix_la_SOURCES += create.cc +libircd_matrix_la_SOURCES += device.cc +libircd_matrix_la_SOURCES += display_name.cc +libircd_matrix_la_SOURCES += event_append.cc +libircd_matrix_la_SOURCES += event_horizon.cc +libircd_matrix_la_SOURCES += events.cc +libircd_matrix_la_SOURCES += fed.cc +libircd_matrix_la_SOURCES += feds.cc +libircd_matrix_la_SOURCES += fetch.cc +libircd_matrix_la_SOURCES += ignored_user_list.cc +libircd_matrix_la_SOURCES += init_backfill.cc +libircd_matrix_la_SOURCES += init_bootstrap.cc +libircd_matrix_la_SOURCES += join.cc +libircd_matrix_la_SOURCES += keys.cc +libircd_matrix_la_SOURCES += leave.cc +libircd_matrix_la_SOURCES += node.cc +libircd_matrix_la_SOURCES += presence.cc +libircd_matrix_la_SOURCES += pretty.cc +libircd_matrix_la_SOURCES += receipt.cc +libircd_matrix_la_SOURCES += room_aliases.cc +libircd_matrix_la_SOURCES += room_auth.cc +libircd_matrix_la_SOURCES += room_bootstrap.cc +libircd_matrix_la_SOURCES += room_events.cc +libircd_matrix_la_SOURCES += room_head.cc +libircd_matrix_la_SOURCES += room_history_visibility.cc +libircd_matrix_la_SOURCES += rooms.cc +libircd_matrix_la_SOURCES += room_server_acl.cc +libircd_matrix_la_SOURCES += rooms_summary.cc +libircd_matrix_la_SOURCES += typing.cc +libircd_matrix_la_SOURCES += user_account_data.cc +libircd_matrix_la_SOURCES += user_events.cc +libircd_matrix_la_SOURCES += user_filter.cc +libircd_matrix_la_SOURCES += user_highlight.cc +libircd_matrix_la_SOURCES += user_mitsein.cc +libircd_matrix_la_SOURCES += user_profile.cc +libircd_matrix_la_SOURCES += user_register.cc +libircd_matrix_la_SOURCES += user_room_account_data.cc +libircd_matrix_la_SOURCES += user_rooms.cc +libircd_matrix_la_SOURCES += user_room_tags.cc +libircd_matrix_la_SOURCES += users.cc +libircd_matrix_la_SOURCES += users_servers.cc +libircd_matrix_la_SOURCES += conf.cc # # Unit configurations diff --git a/matrix/breadcrumb_rooms.cc b/matrix/breadcrumb_rooms.cc new file mode 100644 index 000000000..a241a2d1a --- /dev/null +++ b/matrix/breadcrumb_rooms.cc @@ -0,0 +1,75 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2019 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. + +ircd::m::event::id::buf +IRCD_MODULE_EXPORT +ircd::m::breadcrumb_rooms::set(const json::array &rooms) +const +{ + const json::strung object + { + json::members + { + { "rooms", rooms } + } + }; + + return account_data.set("im.vector.riot.breadcrumb_rooms", object); +} + +bool +IRCD_MODULE_EXPORT +ircd::m::breadcrumb_rooms::for_each(const closure_bool &closure) +const +{ + bool ret{true}; + get(std::nothrow, [&closure, &ret] + (const json::array &rooms) + { + for(const json::string &room : rooms) + if(!closure(room)) + { + ret = false; + break; + } + }); + + return ret; +} + +void +IRCD_MODULE_EXPORT +ircd::m::breadcrumb_rooms::get(const closure &closure) +const +{ + if(!get(std::nothrow, closure)) + throw m::NOT_FOUND + { + "User has no breadcrumb_rooms set in their account_data." + }; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::breadcrumb_rooms::get(std::nothrow_t, + const closure &closure) +const +{ + return account_data.get(std::nothrow, "im.vector.riot.breadcrumb_rooms", [&closure] + (const string_view &key, const json::object &object) + { + const json::array &rooms + { + object["rooms"] + }; + + closure(rooms); + }); +} diff --git a/modules/conf.cc b/matrix/conf.cc similarity index 95% rename from modules/conf.cc rename to matrix/conf.cc index 2caa7d295..1b30f1610 100644 --- a/modules/conf.cc +++ b/matrix/conf.cc @@ -25,19 +25,17 @@ conf_on_init_iter end(conf::on_init) }; -mapi::header -IRCD_MODULE +void conf_on_init() { - "Server Configuration", [] - { - conf_on_init_iter = conf::on_init.emplace(end(conf::on_init), init_conf_item); - reload_conf(); - }, [] - { - assert(conf_on_init_iter != end(conf::on_init)); - conf::on_init.erase(conf_on_init_iter); - } -}; + conf_on_init_iter = conf::on_init.emplace(end(conf::on_init), init_conf_item); + reload_conf(); +} + +void conf_on_fini() +{ + assert(conf_on_init_iter != end(conf::on_init)); + conf::on_init.erase(conf_on_init_iter); +} /// Set to false to quiet errors from a conf item failing to set bool diff --git a/modules/m_create.cc b/matrix/create.cc similarity index 99% rename from modules/m_create.cc rename to matrix/create.cc index f377b7b3f..44c498a65 100644 --- a/modules/m_create.cc +++ b/matrix/create.cc @@ -27,12 +27,6 @@ struct ircd::m::report_error args&&... a); }; -ircd::mapi::header -IRCD_MODULE -{ - "Matrix create room" -}; - decltype(ircd::m::createroom::version_default) IRCD_MODULE_EXPORT_DATA ircd::m::createroom::version_default diff --git a/matrix/device.cc b/matrix/device.cc new file mode 100644 index 000000000..df970a09d --- /dev/null +++ b/matrix/device.cc @@ -0,0 +1,310 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2019 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. + +std::map +IRCD_MODULE_EXPORT +ircd::m::device::count_one_time_keys(const user &user, + const string_view &device_id) +{ + std::map ret; + for_each(user, device_id, [&ret] + (const string_view &type) + { + if(!startswith(type, "one_time_key|")) + return true; + + const auto &[prefix, ident] + { + split(type, '|') + }; + + const auto &[algorithm, name] + { + split(ident, ':') + }; + + assert(prefix == "one_time_key"); + assert(!empty(algorithm)); + assert(!empty(ident)); + assert(!empty(name)); + + auto it(ret.lower_bound(algorithm)); + if(it == end(ret) || it->first != algorithm) + it = ret.emplace_hint(it, algorithm, 0L); + + auto &count(it->second); + ++count; + return true; + }); + + return ret; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::device::set(const m::user &user, + const device &device) +{ + const user::room user_room{user}; + const string_view &device_id + { + json::at<"device_id"_>(device) + }; + + json::for_each(device, [&user, &user_room, &device_id] + (const auto &prop, auto &&val) + { + if(!json::defined(json::value(val))) + return; + + char buf[m::event::TYPE_MAX_SIZE]; + const string_view type{fmt::sprintf + { + buf, "ircd.device.%s", prop + }}; + + m::send(user_room, user, type, device_id, json::members + { + { "", val } + }); + }); + + return true; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::device::set(const m::user &user, + const string_view &id, + const string_view &prop, + const string_view &val) +{ + char buf[m::event::TYPE_MAX_SIZE]; + const string_view type{fmt::sprintf + { + buf, "ircd.device.%s", prop + }}; + + const user::room user_room{user}; + m::send(user_room, user, type, id, json::members + { + { "", val } + }); + + return true; +} + +/// To delete a device we iterate the user's room state for all types matching +/// ircd.device.* (and ircd.device) which have a state_key of the device_id. +/// Those events are redacted which removes them from appearing in the state. +bool +IRCD_MODULE_EXPORT +ircd::m::device::del(const m::user &user, + const string_view &id) +{ + const user::room user_room{user}; + const room::state state{user_room}; + const room::state::type_prefix type + { + "ircd.device." + }; + + state.for_each(type, [&user, &id, &user_room, &state] + (const string_view &type, const string_view &, const event::idx &) + { + const auto event_idx + { + state.get(std::nothrow, type, id) + }; + + const auto event_id + { + m::event_id(event_idx, std::nothrow) + }; + + if(event_id) + m::redact(user_room, user, event_id, "deleted"); + + return true; + }); + + return true; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::device::has(const m::user &user, + const string_view &id) +{ + const user::room user_room{user}; + const room::state state{user_room}; + const room::state::type_prefix type + { + "ircd.device." + }; + + bool ret(false); + state.for_each(type, [&state, &id, &ret] + (const string_view &type, const string_view &, const event::idx &) + { + ret = state.has(type, id); + return !ret; + }); + + return ret; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::device::has(const m::user &user, + const string_view &id, + const string_view &prop) +{ + bool ret{false}; + get(std::nothrow, user, id, prop, [&ret] + (const string_view &value) + { + ret = !empty(value); + }); + + return ret; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::device::get(std::nothrow_t, + const m::user &user, + const string_view &id, + const string_view &prop, + const closure &closure) +{ + char buf[m::event::TYPE_MAX_SIZE]; + const string_view type{fmt::sprintf + { + buf, "ircd.device.%s", prop + }}; + + const m::user::room user_room{user}; + const m::room::state state{user_room}; + const auto event_idx + { + state.get(std::nothrow, type, id) + }; + + return m::get(std::nothrow, event_idx, "content", [&closure] + (const json::object &content) + { + const string_view &value + { + content.get("") + }; + + closure(value); + }); +} + +bool +IRCD_MODULE_EXPORT +ircd::m::device::for_each(const m::user &user, + const string_view &device_id, + const closure_bool &closure) +{ + const m::user::room user_room{user}; + const m::room::state state{user_room}; + const room::state::type_prefix type + { + "ircd.device." + }; + + return state.for_each(type, [&state, &device_id, &closure] + (const string_view &type, const string_view &, const event::idx &) + { + const string_view &prop + { + lstrip(type, "ircd.device.") + }; + + return state.has(type, device_id)? + closure(prop): + true; + }); +} + +bool +IRCD_MODULE_EXPORT +ircd::m::device::for_each(const m::user &user, + const closure_bool &closure) +{ + const m::user::room user_room + { + user + }; + + const m::room::state state + { + user_room + }; + + return state.for_each("ircd.device.device_id", [&closure] + (const string_view &, const string_view &state_key, const event::idx &) + { + return closure(state_key); + }); +} + +ircd::m::device::id::buf +IRCD_MODULE_EXPORT +ircd::m::device::access_token_to_id(const string_view &token) +{ + id::buf ret; + access_token_to_id(token, [&ret] + (const string_view &device_id) + { + ret = device_id; + }); + + return ret; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::device::access_token_to_id(const string_view &token, + const closure &closure) +{ + const m::room::state &state{m::user::tokens}; + const m::event::idx &event_idx + { + state.get(std::nothrow, "ircd.access_token", token) + }; + + bool ret{false}; + const auto device_id{[&closure, &ret] + (const json::object &content) + { + const json::string &device_id + { + content["device_id"] + }; + + if(likely(device_id)) + { + closure(device_id); + ret = true; + } + }}; + + if(!event_idx) + return ret; + + if(!m::get(std::nothrow, event_idx, "content", device_id)) + return ret; + + return ret; +} diff --git a/modules/m_room.cc b/matrix/display_name.cc similarity index 92% rename from modules/m_room.cc rename to matrix/display_name.cc index fc76a6893..427ab778e 100644 --- a/modules/m_room.cc +++ b/matrix/display_name.cc @@ -8,17 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -// NOTE: !!! -// Definitions re currently split between libircd and modules until the API -// and dependency graph has stabilized. Eventually most/all of ircd::m:: -// should migrate out of libircd into modules. - -ircd::mapi::header -IRCD_MODULE -{ - "Matrix room library" -}; - ircd::string_view IRCD_MODULE_EXPORT ircd::m::display_name(const mutable_buffer &out, diff --git a/modules/m_event_append.cc b/matrix/event_append.cc similarity index 98% rename from modules/m_event_append.cc rename to matrix/event_append.cc index b7b65a56d..67cfba2dd 100644 --- a/modules/m_event_append.cc +++ b/matrix/event_append.cc @@ -8,12 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix Event Library :Streaming tools" -}; - namespace ircd::m { extern const event::keys::exclude event_append_exclude_keys; diff --git a/modules/m_event_horizon.cc b/matrix/event_horizon.cc similarity index 95% rename from modules/m_event_horizon.cc rename to matrix/event_horizon.cc index 84773e957..68e93334f 100644 --- a/modules/m_event_horizon.cc +++ b/matrix/event_horizon.cc @@ -14,12 +14,6 @@ namespace ircd::m::dbs void _index_event_horizon(db::txn &, const event &, const write_opts &, const m::event::id &); } -ircd::mapi::header -IRCD_MODULE -{ - "Matrix event horizon library" -}; - size_t ircd::m::event::horizon::rebuild() { diff --git a/modules/m_events.cc b/matrix/events.cc similarity index 99% rename from modules/m_events.cc rename to matrix/events.cc index a795fba07..7c60bc201 100644 --- a/modules/m_events.cc +++ b/matrix/events.cc @@ -13,12 +13,6 @@ namespace ircd::m::events extern conf::item dump_buffer_size; } -ircd::mapi::header -IRCD_MODULE -{ - "Matrix events library" -}; - decltype(ircd::m::events::dump_buffer_size) ircd::m::events::dump_buffer_size { diff --git a/modules/m_feds.cc b/matrix/feds.cc similarity index 97% rename from modules/m_feds.cc rename to matrix/feds.cc index 6ba8f4144..b5b210ad9 100644 --- a/modules/m_feds.cc +++ b/matrix/feds.cc @@ -8,14 +8,6 @@ // 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 :General Library and Utils" -}; - namespace ircd::m::feds { struct request_base; @@ -37,8 +29,6 @@ namespace ircd::m::feds static request_list version(const opts &, const closure &); static request_list keys(const opts &, const closure &); static request_list send(const opts &, const closure &); - - bool execute(const vector_view &opts, const closure &closure); } // @@ -101,10 +91,10 @@ noexcept // m/feds.h // -bool IRCD_MODULE_EXPORT -ircd::m::feds::execute(const vector_view &optsv, - const closure &closure) +ircd::m::feds::execute::execute(const vector_view &optsv, + const closure &closure) +:boolean{true} { request_list list; for(const auto &opts : optsv) switch(opts.op) @@ -150,7 +140,7 @@ ircd::m::feds::execute(const vector_view &optsv, if(opts.timeout > timeout) timeout = opts.timeout; - return handler(list, timeout, closure); + this->boolean::val = handler(list, timeout, closure); } ircd::m::feds::request_list diff --git a/modules/m_fetch.cc b/matrix/fetch.cc similarity index 99% rename from modules/m_fetch.cc rename to matrix/fetch.cc index 612314663..8d0a94bb2 100644 --- a/modules/m_fetch.cc +++ b/matrix/fetch.cc @@ -50,12 +50,6 @@ namespace ircd::m::fetch static void fini(); } -ircd::mapi::header -IRCD_MODULE -{ - "Event Fetch Unit", ircd::m::fetch::init, ircd::m::fetch::fini -}; - decltype(ircd::m::fetch::log) ircd::m::fetch::log { diff --git a/matrix/ignored_user_list.cc b/matrix/ignored_user_list.cc new file mode 100644 index 000000000..d92be62d6 --- /dev/null +++ b/matrix/ignored_user_list.cc @@ -0,0 +1,91 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2019 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 +{ + extern conf::item ignored_user_list_enforce_invites; + extern conf::item ignored_user_list_enforce_events; +} + +decltype(ircd::m::ignored_user_list_enforce_invites) +ircd::m::ignored_user_list_enforce_invites +{ + { "name", "ircd.m.ignored_user_list.enforce.invites" }, + { "default", true } +}; + +decltype(ircd::m::ignored_user_list_enforce_events) +ircd::m::ignored_user_list_enforce_events +{ + { "name", "ircd.m.ignored_user_list.enforce.events" }, + { "default", false } +}; + +bool +IRCD_MODULE_EXPORT +ircd::m::user::ignores::has(const m::user::id &other) +const +{ + return !for_each([&other] + (const m::user::id &user_id, const json::object &) + { + return user_id != other; + }); +} + +bool +IRCD_MODULE_EXPORT +ircd::m::user::ignores::for_each(const closure_bool &closure) +const try +{ + const m::user::account_data account_data + { + user + }; + + bool ret{true}; + account_data.get(std::nothrow, "m.ignored_user_list", [&closure, &ret] + (const string_view &key, const json::object &content) + { + const json::object &ignored_users + { + content.get("ignored_users") + }; + + for(const auto &[user_id, object] : ignored_users) + if(!(ret = closure(user_id, object))) + return; + }); + + return ret; +} +catch(const std::exception &e) +{ + log::derror + { + m::log, "Error in ignore list for %s", + string_view{user.user_id} + }; + + return true; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::user::ignores::enforce(const string_view &type) +{ + if(type == "events") + return bool(ignored_user_list_enforce_events); + + if(type == "invites") + return bool(ignored_user_list_enforce_invites); + + return false; +} diff --git a/modules/m_init_backfill.cc b/matrix/init_backfill.cc similarity index 98% rename from modules/m_init_backfill.cc rename to matrix/init_backfill.cc index ac8240f81..b7050b3cf 100644 --- a/modules/m_init_backfill.cc +++ b/matrix/init_backfill.cc @@ -26,14 +26,6 @@ struct ircd::m::init::backfill static log::log log; }; -ircd::mapi::header -IRCD_MODULE -{ - "Matrix resynchronization backfilling", - ircd::m::init::backfill::init, - ircd::m::init::backfill::fini, -}; - decltype(ircd::m::init::backfill::log) ircd::m::init::backfill::log { diff --git a/modules/m_room_join.cc b/matrix/join.cc similarity index 98% rename from modules/m_room_join.cc rename to matrix/join.cc index 0daf24fa2..0c1d7a219 100644 --- a/modules/m_room_join.cc +++ b/matrix/join.cc @@ -8,12 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix room join" -}; - ircd::m::event::id::buf IRCD_MODULE_EXPORT ircd::m::join(const room::alias &room_alias, diff --git a/modules/m_keys.cc b/matrix/keys.cc similarity index 99% rename from modules/m_keys.cc rename to matrix/keys.cc index e2e8d4ed0..8afe66876 100644 --- a/modules/m_keys.cc +++ b/matrix/keys.cc @@ -8,13 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Server keys" - ,ircd::m::self::init::keys -}; - std::ostream & IRCD_MODULE_EXPORT ircd::m::pretty_oneline(std::ostream &s, diff --git a/modules/m_room_leave.cc b/matrix/leave.cc similarity index 96% rename from modules/m_room_leave.cc rename to matrix/leave.cc index c7486eebd..13f676bd6 100644 --- a/modules/m_room_leave.cc +++ b/matrix/leave.cc @@ -8,12 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix room leave" -}; - ircd::m::event::id::buf IRCD_MODULE_EXPORT ircd::m::leave(const room &room, diff --git a/matrix/matrix.cc b/matrix/matrix.cc index 9ee1af22f..15d95a1f2 100644 --- a/matrix/matrix.cc +++ b/matrix/matrix.cc @@ -198,69 +198,34 @@ noexcept decltype(ircd::m::module_names) ircd::m::module_names { - "m_node", - "m_keys", - "m_event", - "m_fetch", - "m_feds", - - "m_room", - "m_room_events", - "m_room_auth", - "m_room_head", - "m_room_bootstrap", - "m_room_join", - "m_room_leave", + "m_noop", + "m_breadcrumb_rooms", + "m_command", + "m_control", + "m_device", + "m_device_list_update", + "m_direct", + "m_direct_to_device", + "m_ignored_user_list", + "m_init_backfill", + "m_listen", + "m_presence", + "m_profile", + "m_receipt", "m_room_aliases", "m_room_canonical_alias", "m_room_create", "m_room_history_visibility", "m_room_join_rules", "m_room_member", - "m_room_name", - "m_room_third_party_invite", "m_room_message", + "m_room_name", "m_room_power_levels", - "m_room_server_acl", "m_room_redaction", + "m_room_server_acl", + "m_room_third_party_invite", + "m_user_highlight_auth", - "m_user", - "m_user_filter", - "m_user_rooms", - "m_user_mitsein", - "m_user_servers", - "m_user_events", - "m_user_highlight", - "m_user_profile", - "m_user_account_data", - "m_user_room_account_data", - "m_user_room_tags", - "m_user_register", - - "m_events", - "m_rooms", - "m_rooms_summary", - "m_users", - "m_presence", - "m_receipt", - "m_typing", - "m_device_list_update", - "m_device", - "m_direct", - "m_direct_to_device", - "m_breadcrumb_rooms", - "m_ignored_user_list", - "m_command", - "m_control", - "m_create", - "m_profile", - "m_noop", - - "m_event_append", - "m_event_horizon", - "m_event_pretty", - - "conf", "net_dns", "key_query", "key_server", @@ -350,7 +315,6 @@ ircd::m::module_names "stats", "m_vm_fetch", "m_vm", - "m_init_backfill", "m_listen", }; @@ -453,7 +417,7 @@ ircd::m::self::host(const string_view &other) // port() is 0 when the origin has no port (and implies 8448) const auto port { - me.user_id.port() + net::port(hostport(origin)) }; // If my_host has a port number, then the argument must also have the @@ -478,7 +442,7 @@ ircd::m::self::host(const string_view &other) ircd::string_view ircd::m::self::host() { - return me.user_id.host(); + return m::self::origin; } // @@ -525,7 +489,7 @@ try // inits of m::self::globals. Calling the inits directly from // here makes the module dependent on libircd and unloadable. assert(ircd::run::level == run::level::START); - mods::imports.emplace("m_keys"s, "m_keys"s); + m::self::init::keys(); } catch(const std::exception &e) { @@ -1054,33 +1018,6 @@ ircd::m::app::exists(const string_view &id) return call(id); } -/////////////////////////////////////////////////////////////////////////////// -// -// m/feds.h -// - -ircd::m::feds::execute::execute(const opts &o, - const closure &c) -:execute -{ - vector_view{&o, 1}, c -} -{ -} - -ircd::m::feds::execute::execute(const vector_view &o, - const closure &c) -{ - using prototype = bool (const vector_view &, const closure &); - - static mods::import call - { - "m_feds", "ircd::m::feds::execute" - }; - - call(o, c); -} - /////////////////////////////////////////////////////////////////////////////// // // m/vm.h @@ -1741,19 +1678,6 @@ ircd::m::presence::set(const user &user, }); } -ircd::m::event::id::buf -ircd::m::presence::set(const presence &object) -{ - using prototype = event::id::buf (const presence &); - - static mods::import function - { - "m_presence", "ircd::m::presence::set" - }; - - return function(object); -} - void ircd::m::presence::get(const user &user, const closure &closure) @@ -1784,22 +1708,6 @@ ircd::m::presence::get(std::nothrow_t, return get(std::nothrow, user, reclosure, &fopts); } -bool -ircd::m::presence::get(std::nothrow_t, - const user &user, - const closure_event &closure, - const event::fetch::opts *const &opts) -{ - using prototype = bool (std::nothrow_t, const m::user &, const closure_event &, const event::fetch::opts *const &); - - static mods::import function - { - "m_presence", "ircd::m::presence::get" - }; - - return function(std::nothrow, user, closure, opts); -} - ircd::m::event::idx ircd::m::presence::get(const user &user) { @@ -1817,111 +1725,11 @@ ircd::m::presence::get(const user &user) return ret; } -ircd::m::event::idx -ircd::m::presence::get(std::nothrow_t, - const user &user) -{ - using prototype = event::idx (std::nothrow_t, const m::user &); - - static mods::import function - { - "m_presence", "ircd::m::presence::get" - }; - - return function(std::nothrow, user); -} - -bool -ircd::m::presence::valid_state(const string_view &state) -{ - using prototype = bool (const string_view &); - - static mods::import function - { - "m_presence", "ircd::m::presence::valid_state" - }; - - return function(state); -} - /////////////////////////////////////////////////////////////////////////////// // // m/device.h // -bool -ircd::m::device::set(const m::user &user, - const device &device_) -{ - using prototype = bool (const m::user &, const device &); - - static mods::import function - { - "m_device", "ircd::m::device::set" - }; - - return function(user, device_); -} - -bool -ircd::m::device::set(const m::user &user, - const string_view &id, - const string_view &prop, - const string_view &val) -{ - using prototype = bool (const m::user &, const string_view &, const string_view &, const string_view &); - - static mods::import function - { - "m_device", "ircd::m::device::set" - }; - - return function(user, id, prop, val); -} - -bool -ircd::m::device::del(const m::user &user, - const string_view &id) -{ - using prototype = bool (const m::user &, const string_view &); - - static mods::import function - { - "m_device", "ircd::m::device::del" - }; - - return function(user, id); -} - -bool -ircd::m::device::has(const m::user &user, - const string_view &id) -{ - using prototype = bool (const m::user &, const string_view &id); - - static mods::import function - { - "m_device", "ircd::m::device::has" - }; - - return function(user, id); -} - -bool -ircd::m::device::has(const m::user &user, - const string_view &id, - const string_view &prop) -{ - using prototype = bool (const m::user &, const string_view &id, const string_view &prop); - - static mods::import function - { - "m_device", "ircd::m::device::has" - }; - - return function(user, id, prop); -} - bool ircd::m::device::get(const m::user &user, const string_view &id, @@ -1945,56 +1753,6 @@ ircd::m::device::get(const m::user &user, return ret; } -bool -ircd::m::device::get(std::nothrow_t, - const m::user &user, - const string_view &id, - const string_view &prop, - const closure &c) -{ - using prototype = bool (std::nothrow_t, - const m::user &, - const string_view &, - const string_view &, - const closure &); - - static mods::import function - { - "m_device", "ircd::m::device::get" - }; - - return function(std::nothrow, user, id, prop, c); -} - -bool -ircd::m::device::for_each(const m::user &user, - const string_view &id, - const closure_bool &c) -{ - using prototype = bool (const m::user &, const string_view &id, const closure_bool &); - - static mods::import function - { - "m_device", "ircd::m::device::for_each" - }; - - return function(user, id, c); -} - -bool -ircd::m::device::for_each(const m::user &user, - const closure_bool &c) -{ - using prototype = bool (const m::user &, const closure_bool &); - - static mods::import function - { - "m_device", "ircd::m::device::for_each" - }; - - return function(user, c); -} - /////////////////////////////////////////////////////////////////////////////// // // m/node.h @@ -2035,15 +1793,7 @@ ircd::m::node::key(const string_view &key_id, const key_closure &closure) const { - using prototype = void (const string_view &, const string_view &, const keys::closure &); - - //TODO: Remove this import once this callsite is outside of libircd. - static mods::import call - { - "m_keys", "ircd::m::keys::get" - }; - - call(node_id, key_id, [&closure, &key_id] + m::keys::get(node_id, key_id, [&closure, &key_id] (const json::object &keys) { const json::object &vks diff --git a/modules/m_node.cc b/matrix/node.cc similarity index 93% rename from modules/m_node.cc rename to matrix/node.cc index 365fc740e..74fd8f958 100644 --- a/modules/m_node.cc +++ b/matrix/node.cc @@ -8,16 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Server Nodes" -}; - -// -// node -// - ircd::m::node IRCD_MODULE_EXPORT ircd::m::create(const node &node, diff --git a/matrix/presence.cc b/matrix/presence.cc new file mode 100644 index 000000000..39576f3c1 --- /dev/null +++ b/matrix/presence.cc @@ -0,0 +1,105 @@ +// 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. + +namespace ircd::m +{ + extern const string_view presence_valid_states[]; +} + +decltype(ircd::m::presence_valid_states) +ircd::m::presence_valid_states +{ + "online", + "offline", + "unavailable", +}; + +bool +IRCD_MODULE_EXPORT +ircd::m::presence::get(const std::nothrow_t, + const m::user &user, + const m::presence::closure_event &closure, + const m::event::fetch::opts *const &fopts_p) +{ + const m::event::idx event_idx + { + m::presence::get(std::nothrow, user) + }; + + if(!event_idx) + return false; + + const auto &fopts + { + fopts_p? *fopts_p : event::fetch::default_opts + }; + + const m::event::fetch event + { + event_idx, std::nothrow, fopts + }; + + if(event.valid) + closure(event); + + return event.valid; +} + +ircd::m::event::idx +IRCD_MODULE_EXPORT +ircd::m::presence::get(const std::nothrow_t, + const m::user &user) +{ + const m::user::room user_room + { + user + }; + + const m::room::state state + { + user_room + }; + + return state.get(std::nothrow, "ircd.presence", ""); +} + +ircd::m::event::id::buf +IRCD_MODULE_EXPORT +ircd::m::presence::set(const m::presence &content) +{ + const m::user user + { + json::at<"user_id"_>(content) + }; + + //TODO: ABA + if(!exists(user)) + create(user.user_id); + + m::vm::copts copts; + const m::user::room user_room + { + user, &copts + }; + + //TODO: ABA + return send(user_room, user.user_id, "ircd.presence", "", json::strung{content}); +} + +bool +IRCD_MODULE_EXPORT +ircd::m::presence::valid_state(const string_view &state) +{ + return std::any_of(begin(presence_valid_states), end(presence_valid_states), [&state] + (const string_view &valid) + { + return state == valid; + }); +} diff --git a/modules/m_event_pretty.cc b/matrix/pretty.cc similarity index 97% rename from modules/m_event_pretty.cc rename to matrix/pretty.cc index 3ca3d4031..f26b5aadb 100644 --- a/modules/m_event_pretty.cc +++ b/matrix/pretty.cc @@ -8,12 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix event pretty printing library" -}; - std::ostream & IRCD_MODULE_EXPORT ircd::m::pretty_stateline(std::ostream &out, diff --git a/matrix/receipt.cc b/matrix/receipt.cc new file mode 100644 index 000000000..267dd38dc --- /dev/null +++ b/matrix/receipt.cc @@ -0,0 +1,194 @@ +// 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. + +decltype(ircd::m::receipt::log) +IRCD_MODULE_EXPORT_DATA +ircd::m::receipt::log +{ + "m.receipt" +}; + +ircd::m::event::id::buf +IRCD_MODULE_EXPORT +ircd::m::receipt::read(const m::room::id &room_id, + const m::user::id &user_id, + const m::event::id &event_id, + const json::object &options) +{ + const m::user::room user_room + { + user_id + }; + + const auto evid + { + send(user_room, user_id, "ircd.read", room_id, + { + { "event_id", event_id }, + { "ts", options.get("ts", ircd::time()) }, + { "m.hidden", options.get("m.hidden", false) }, + }) + }; + + log::info + { + log, "%s read by %s in %s options:%s", + string_view{event_id}, + string_view{user_id}, + string_view{room_id}, + string_view{options}, + }; + + return evid; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::receipt::get(const m::room::id &room_id, + const m::user::id &user_id, + const m::event::id::closure &closure) +{ + const m::user::room user_room + { + user_id + }; + + const auto event_idx + { + user_room.get(std::nothrow, "ircd.read", room_id) + }; + + return m::get(std::nothrow, event_idx, "content", [&closure] + (const json::object &content) + { + const json::string &event_id + { + content["event_id"] + }; + + closure(event_id); + }); +} + + +/// Does the user wish to not send receipts for events sent by its specific +/// sender? +bool +IRCD_MODULE_EXPORT +ircd::m::receipt::ignoring(const m::user &user, + const m::event::id &event_id) +{ + bool ret{false}; + m::get(std::nothrow, event_id, "sender", [&ret, &user] + (const string_view &sender) + { + const m::user::room user_room{user}; + ret = user_room.has("ircd.read.ignore", sender); + }); + + return ret; +} + +/// Does the user wish to not send receipts for events for this entire room? +bool +IRCD_MODULE_EXPORT +ircd::m::receipt::ignoring(const m::user &user, + const m::room::id &room_id) +{ + const m::user::room user_room{user}; + return user_room.has("ircd.read.ignore", room_id); +} + +bool +IRCD_MODULE_EXPORT +ircd::m::receipt::freshest(const m::room::id &room_id, + const m::user::id &user_id, + const m::event::id &event_id) +try +{ + const m::user::room user_room + { + user_id + }; + + bool ret{true}; + user_room.get("ircd.read", room_id, [&ret, &event_id] + (const m::event &event) + { + const auto &content + { + at<"content"_>(event) + }; + + const m::event::id &previous_id + { + unquote(content.get("event_id")) + }; + + if(event_id == previous_id) + { + ret = false; + return; + } + + const m::event::idx &previous_idx + { + index(previous_id) + }; + + const m::event::idx &event_idx + { + index(event_id) + }; + + ret = event_idx > previous_idx; + }); + + return ret; +} +catch(const std::exception &e) +{ + log::derror + { + log, "Freshness of receipt in %s from %s for %s :%s", + string_view{room_id}, + string_view{user_id}, + string_view{event_id}, + e.what() + }; + + return true; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::receipt::exists(const m::room::id &room_id, + const m::user::id &user_id, + const m::event::id &event_id) +{ + const m::user::room user_room + { + user_id + }; + + bool ret{false}; + user_room.get(std::nothrow, "ircd.read", room_id, [&ret, &event_id] + (const m::event &event) + { + const auto &content + { + at<"content"_>(event) + }; + + ret = unquote(content.get("event_id")) == event_id; + }); + + return ret; +} diff --git a/matrix/room.cc b/matrix/room.cc index 40ba4500a..45d4a4454 100644 --- a/matrix/room.cc +++ b/matrix/room.cc @@ -312,48 +312,6 @@ ircd::m::create(const id::room &room_id, }); } -ircd::m::event::id::buf -ircd::m::join(const id::room_alias &room_alias, - const id::user &user_id) -{ - using prototype = event::id::buf (const id::room_alias &, const id::user &); - - static mods::import function - { - "m_room_join", "ircd::m::join" - }; - - return function(room_alias, user_id); -} - -ircd::m::event::id::buf -ircd::m::join(const room &room, - const id::user &user_id) -{ - using prototype = event::id::buf (const m::room &, const id::user &); - - static mods::import function - { - "m_room_join", "ircd::m::join" - }; - - return function(room, user_id); -} - -ircd::m::event::id::buf -ircd::m::leave(const room &room, - const id::user &user_id) -{ - using prototype = event::id::buf (const m::room &, const id::user &); - - static mods::import function - { - "m_room_leave", "ircd::m::leave" - }; - - return function(room, user_id); -} - ircd::m::event::id::buf ircd::m::invite(const room &room, const id::user &target, @@ -3548,52 +3506,10 @@ const return for_each(room, server, closure); } -bool -ircd::m::room::aliases::for_each(const m::room &room, - const string_view &server, - const closure_bool &closure) -{ - using prototype = bool (const m::room &, const string_view &, const closure_bool &); - - static mods::import call - { - "m_room_aliases", "ircd::m::room::aliases::for_each" - }; - - return call(room, server, closure); -} - // // room::aliases::cache // -bool -ircd::m::room::aliases::cache::del(const alias &a) -{ - using prototype = bool (const alias &); - - static mods::import call - { - "m_room_aliases", "ircd::m::room::aliases::cache::del" - }; - - return call(a); -} - -bool -ircd::m::room::aliases::cache::set(const alias &a, - const id &i) -{ - using prototype = bool (const alias &, const id &); - - static mods::import call - { - "m_room_aliases", "ircd::m::room::aliases::cache::set" - }; - - return call(a, i); -} - bool ircd::m::room::aliases::cache::fetch(std::nothrow_t, const alias &a, @@ -3617,20 +3533,6 @@ catch(const std::exception &e) return false; } -void -ircd::m::room::aliases::cache::fetch(const alias &a, - const net::hostport &hp) -{ - using prototype = void (const alias &, const net::hostport &); - - static mods::import call - { - "m_room_aliases", "ircd::m::room::aliases::cache::fetch" - }; - - return call(a, hp); -} - ircd::m::room::id::buf ircd::m::room::aliases::cache::get(const alias &a) { @@ -3670,54 +3572,12 @@ ircd::m::room::aliases::cache::get(const alias &a, }; } -bool -ircd::m::room::aliases::cache::get(std::nothrow_t, - const alias &a, - const id::closure &c) -{ - using prototype = bool (std::nothrow_t, const alias &, const id::closure &); - - static mods::import call - { - "m_room_aliases", "ircd::m::room::aliases::cache::get" - }; - - return call(std::nothrow, a, c); -} - -bool -ircd::m::room::aliases::cache::has(const alias &a) -{ - using prototype = bool (const alias &); - - static mods::import call - { - "m_room_aliases", "ircd::m::room::aliases::cache::has" - }; - - return call(a); -} - bool ircd::m::room::aliases::cache::for_each(const closure_bool &c) { return for_each(string_view{}, c); } -bool -ircd::m::room::aliases::cache::for_each(const string_view &s, - const closure_bool &c) -{ - using prototype = bool (const string_view &, const closure_bool &); - - static mods::import call - { - "m_room_aliases", "ircd::m::room::aliases::cache::for_each" - }; - - return call(s, c); -} - // // room::power // diff --git a/matrix/room_aliases.cc b/matrix/room_aliases.cc new file mode 100644 index 000000000..cf8341c33 --- /dev/null +++ b/matrix/room_aliases.cc @@ -0,0 +1,465 @@ +// 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. + +namespace ircd::m +{ + extern conf::item alias_fetch_timeout; + extern conf::item alias_cache_ttl; + extern const room::id::buf alias_room_id; + extern const room alias_room; +} + +decltype(ircd::m::alias_room_id) +ircd::m::alias_room_id +{ + "alias", ircd::my_host() +}; + +decltype(ircd::m::alias_room) +ircd::m::alias_room +{ + alias_room_id +}; + +decltype(ircd::m::alias_cache_ttl) +ircd::m::alias_cache_ttl +{ + { "name", "ircd.m.room.aliases.cache.ttl" }, + { "default", 604800L }, +}; + +decltype(ircd::m::alias_fetch_timeout) +ircd::m::alias_fetch_timeout +{ + { "name", "ircd.m.room.aliases.fetch.timeout" }, + { "default", 10L }, +}; + +// +// m::room::aliases +// + +bool +IRCD_MODULE_EXPORT +ircd::m::room::aliases::for_each(const m::room &room, + const string_view &server, + const closure_bool &closure) +{ + const room::state state + { + room + }; + + assert(server); + const event::idx &event_idx + { + state.get(std::nothrow, "m.room.aliases", server) + }; + + if(!event_idx) + return true; + + bool ret{true}; + m::get(std::nothrow, event_idx, "content", [&closure, &ret] + (const json::object &content) + { + const json::array &aliases + { + content["aliases"] + }; + + for(auto it(begin(aliases)); it != end(aliases) && ret; ++it) + { + const json::string &alias(*it); + if(!valid(m::id::ROOM_ALIAS, alias)) + continue; + + if(!closure(alias)) + ret = false; + } + }); + + return ret; +} + +// +// m::room::aliases::cache +// + +bool +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::del(const alias &alias) +{ + char buf[m::id::room_alias::buf::SIZE]; + const string_view &key + { + make_key(buf, alias) + }; + + const auto &event_idx + { + alias_room.get(std::nothrow, "ircd.room.alias", key) + }; + + if(!event_idx) + return false; + + const auto event_id + { + m::event_id(event_idx, std::nothrow) + }; + + if(!event_id) + return false; + + const auto ret + { + redact(alias_room, m::me.user_id, event_id, "deleted") + }; + + return true; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::set(const alias &alias, + const id &id) +{ + char buf[m::id::room_alias::buf::SIZE]; + const string_view &key + { + make_key(buf, alias) + }; + + const auto ret + { + send(alias_room, m::me.user_id, "ircd.room.alias", key, + { + { "room_id", id } + }) + }; + + return true; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::get(std::nothrow_t, + const alias &alias, + const id::closure &closure) +{ + m::event::idx event_idx + { + getidx(alias) + }; + + if(!event_idx) + { + if(my_host(alias.host())) + return false; + + if(!fetch(std::nothrow, alias, alias.host())) + return false; + + event_idx = getidx(alias); + } + + const bool expired + { + !my_host(alias.host()) && cache::expired(event_idx) + }; + + if(expired) + { + log::dwarning + { + log, "Cached alias %s expired age:%ld ttl:%ld", + string_view{alias}, + cache::age(event_idx).count(), + milliseconds(seconds(alias_cache_ttl)).count(), + }; + + fetch(std::nothrow, alias, alias.host()); + event_idx = getidx(alias); + } + + if(!event_idx) + return false; + + bool ret{false}; + m::get(std::nothrow, event_idx, "content", [&closure, &ret] + (const json::object &content) + { + const json::string &room_id + { + content.get("room_id") + }; + + if(!empty(room_id)) + { + ret = true; + closure(room_id); + } + }); + + return ret; +} + +namespace ircd::m +{ + thread_local char room_aliases_cache_fetch_hpbuf[384]; +} + +void +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::fetch(const alias &alias, + const net::hostport &hp) +try +{ + const unique_buffer buf + { + 16_KiB + }; + + m::v1::query::opts opts; + opts.remote = hp; + opts.dynamic = true; + + m::v1::query::directory request + { + alias, buf, std::move(opts) + }; + + request.wait(seconds(alias_fetch_timeout)); + const http::code &code + { + request.get() + }; + + const json::object response + { + request + }; + + if(!response.has("room_id")) + throw m::NOT_FOUND + { + "Server '%s' does not know room_id for %s", + string(room_aliases_cache_fetch_hpbuf, hp), + string_view{alias}, + }; + + const m::room::id &room_id + { + unquote(response["room_id"]) + }; + + set(alias, room_id); +} +catch(const ctx::timeout &e) +{ + throw m::error + { + http::GATEWAY_TIMEOUT, "M_ROOM_ALIAS_TIMEOUT", + "Server '%s' did not respond with a room_id for %s in time", + string(room_aliases_cache_fetch_hpbuf, hp), + string_view{alias}, + }; +} +catch(const server::unavailable &e) +{ + throw m::error + { + http::BAD_GATEWAY, "M_ROOM_ALIAS_UNAVAILABLE", + "Server '%s' is not available to query a room_id for %s", + string(room_aliases_cache_fetch_hpbuf, hp), + string_view{alias}, + }; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::for_each(const string_view &server, + const closure_bool &closure) +{ + const m::room::state state + { + alias_room + }; + + bool ret{true}; + const m::room::state::closure_bool reclosure{[&server, &closure, &ret] + (const string_view &type, const string_view &state_key, const m::event::idx &event_idx) + { + thread_local char swapbuf[m::id::room_alias::buf::SIZE]; + const alias &alias + { + m::id::unswap(state_key, swapbuf) + }; + + if(server && alias.host() != server) + return false; + + if(expired(event_idx)) + return true; + + m::get(std::nothrow, event_idx, "content", [&closure, &ret, &alias] + (const json::object &content) + { + const json::string &room_id + { + content.get("room_id") + }; + + if(!empty(room_id)) + ret = closure(alias, room_id); + }); + + return ret; + }}; + + state.for_each("ircd.room.alias", server, reclosure); + return ret; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::has(const alias &alias) +{ + const auto &event_idx + { + getidx(alias) + }; + + if(!event_idx) + return false; + + if(expired(event_idx)) + return false; + + bool ret{false}; + m::get(std::nothrow, event_idx, "content", [&ret] + (const json::object &content) + { + const json::string &room_id + { + content.get("room_id") + }; + + ret = !empty(room_id); + }); + + return ret; +} + +ircd::system_point +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::expires(const alias &alias) +{ + const auto event_idx + { + getidx(alias) + }; + + if(!event_idx) + return system_point::min(); + + const milliseconds age + { + cache::age(event_idx) + }; + + const seconds ttl + { + alias_cache_ttl + }; + + return now() + (ttl - age); +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::expired(const event::idx &event_idx) +{ + const milliseconds age + { + cache::age(event_idx) + }; + + const seconds ttl + { + alias_cache_ttl + }; + + return age > ttl; +} + +ircd::milliseconds +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::age(const event::idx &event_idx) +{ + time_t ts; + if(!m::get(event_idx, "origin_server_ts", ts)) + return milliseconds::max(); + + const time_t now + { + ircd::time() + }; + + return milliseconds + { + now - ts + }; +} + +ircd::m::event::idx +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::getidx(const alias &alias) +{ + thread_local char swapbuf[m::id::room_alias::buf::SIZE]; + const string_view &swapped + { + alias.swap(swapbuf) + }; + + char buf[m::id::room_alias::buf::SIZE]; + const string_view &key + { + tolower(buf, swapped) + }; + + const auto &event_idx + { + alias_room.get(std::nothrow, "ircd.room.alias", key) + }; + + return event_idx; +} + +ircd::string_view +IRCD_MODULE_EXPORT +ircd::m::room::aliases::cache::make_key(const mutable_buffer &out, + const alias &alias) +{ + + thread_local char swapbuf[m::id::room_alias::buf::SIZE] alignas(16); + const string_view &swapped + { + alias.swap(swapbuf) + }; + + const string_view &key + { + tolower(out, swapped) + }; + + return key; +} diff --git a/modules/m_room_auth.cc b/matrix/room_auth.cc similarity index 99% rename from modules/m_room_auth.cc rename to matrix/room_auth.cc index 64fc21093..e32ccf44e 100644 --- a/modules/m_room_auth.cc +++ b/matrix/room_auth.cc @@ -19,12 +19,6 @@ namespace ircd::m extern hook::site room_auth_hook; } -ircd::mapi::header -IRCD_MODULE -{ - "Matrix room event authentication support." -}; - decltype(ircd::m::room_auth_hook) ircd::m::room_auth_hook { diff --git a/modules/m_room_bootstrap.cc b/matrix/room_bootstrap.cc similarity index 99% rename from modules/m_room_bootstrap.cc rename to matrix/room_bootstrap.cc index 9008fe266..852a77017 100644 --- a/modules/m_room_bootstrap.cc +++ b/matrix/room_bootstrap.cc @@ -36,12 +36,6 @@ struct ircd::m::bootstrap::pkg std::string host; }; -ircd::mapi::header -IRCD_MODULE -{ - "Matrix room bootstrap." -}; - decltype(ircd::m::bootstrap::log) ircd::m::bootstrap::log { diff --git a/modules/m_room_events.cc b/matrix/room_events.cc similarity index 99% rename from modules/m_room_events.cc rename to matrix/room_events.cc index 51b992ed4..6ab699517 100644 --- a/modules/m_room_events.cc +++ b/matrix/room_events.cc @@ -8,12 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix room library" -}; - decltype(ircd::m::room::events::viewport_size) IRCD_MODULE_EXPORT_DATA ircd::m::room::events::viewport_size diff --git a/modules/m_room_head.cc b/matrix/room_head.cc similarity index 98% rename from modules/m_room_head.cc rename to matrix/room_head.cc index 8340cf4c8..2d3213caf 100644 --- a/modules/m_room_head.cc +++ b/matrix/room_head.cc @@ -8,16 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix room head" -}; - -// -// room::head -// - std::pair IRCD_MODULE_EXPORT ircd::m::room::head::generate(const mutable_buffer &buf, diff --git a/matrix/room_history_visibility.cc b/matrix/room_history_visibility.cc new file mode 100644 index 000000000..608e6b5d7 --- /dev/null +++ b/matrix/room_history_visibility.cc @@ -0,0 +1,150 @@ +// 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. + +namespace ircd::m +{ + static bool visible_to_node(const room &, const string_view &node_id, const event &); + static bool visible_to_user(const room &, const string_view &history_visibility, const m::user::id &, const event &); +} + +bool +IRCD_MODULE_EXPORT +ircd::m::visible(const m::event &event, + const string_view &mxid) +{ + const m::room room + { + at<"room_id"_>(event), event.event_id + }; + + const m::room::state state + { + room + }; + + const event::idx visibility_event_idx + { + state.get(std::nothrow, "m.room.history_visibility", "") + }; + + char buf[32]; + string_view history_visibility{"shared"}; + m::get(std::nothrow, visibility_event_idx, "content", [&buf, &history_visibility] + (const json::object &content) + { + const json::string &_history_visibility + { + content.get("history_visibility", "shared") + }; + + history_visibility = strncpy + { + buf, _history_visibility + }; + }); + + if(history_visibility == "world_readable") + return true; + + if(empty(mxid)) + return false; + + if(m::valid(m::id::USER, mxid)) + return visible_to_user(room, history_visibility, mxid, event); + + if(rfc3986::valid_remote(std::nothrow, mxid)) + return visible_to_node(room, mxid, event); + + throw m::UNSUPPORTED + { + "Cannot determine visibility of %s for '%s'", + string_view{room.room_id}, + mxid, + }; +} + +bool +ircd::m::visible_to_user(const m::room &room, + const string_view &history_visibility, + const m::user::id &user_id, + const m::event &event) +{ + assert(history_visibility != "world_readable"); + + // Allow any member event where the state_key string is a user mxid. + if(json::get<"type"_>(event) == "m.room.member") + if(at<"state_key"_>(event) == user_id) + return true; + + // Get the membership of the user in the room at the event. + char buf[m::room::MEMBERSHIP_MAX_SIZE]; + const string_view membership + { + m::membership(buf, room, user_id) + }; + + if(membership == "join") + return true; + + if(history_visibility == "joined") + return false; + + if(membership == "invite") + return true; + + if(history_visibility == "invited") + return false; + + // The history_visibility is now likely "shared"; though we cannot assert + // that in case some other string is used for any non-spec customization + // or for graceful forward compatibility. We default to "shared" here. + //assert(history_visibility == "shared"); + + // An m::room instance with no event_id is used to query the room at the + // present state. + const m::room present + { + room.room_id + }; + + // If the room is not at the present event then we have to run another + // test for membership here. Otherwise the "join" test already failed. + if(!room.event_id) + return false; + + return m::membership(present, user_id, m::membership_positive); // join || invite +} + +bool +ircd::m::visible_to_node(const m::room &room, + const string_view &node_id, + const m::event &event) +{ + // Allow auth chain events XXX: this is too broad + if(m::room::auth::is_power_event(event)) + return true; + + // Allow any event where the state_key string is a user mxid and the server + // is the host of that user. Note that applies to any type of event. + if(m::valid(m::id::USER, json::get<"state_key"_>(event))) + if(m::user::id(at<"state_key"_>(event)).host() == node_id) + return true; + + const m::room::origins origins + { + room + }; + + // Allow joined servers + if(origins.has(node_id)) + return true; + + return false; +} diff --git a/matrix/room_server_acl.cc b/matrix/room_server_acl.cc new file mode 100644 index 000000000..435453c28 --- /dev/null +++ b/matrix/room_server_acl.cc @@ -0,0 +1,332 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2019 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. + +/// Coarse control over whether ACL's are considered during the vm::eval of an +/// event, ACL's will be checked against the event's origin during processing +/// of the event, regardless of how the event was received, fetched, etc. The +/// m::vm options may dictate further detailed behavior (hard-fail, soft- +/// fail, auth integration, etc). This is the principal configuration option +/// for effecting the server access control list functionality. Though this +/// conf item is independent of other conf items in this module, setting it +/// to false denudes the core functionality. +/// +/// Setting this to true is *stricter* than the official specification and +/// fixes several vulnerabilities for bypassing ACL's. This also applies to +/// both PDU's and EDU's, and is agnostic to the method or endpoint by which +/// this server obtained the event. This departs from the specification. +/// +/// This option has no effect on the room::server_acl interface itself, it is +/// available for the callsite to check independently before using the iface. +decltype(ircd::m::room::server_acl::enable_write) +IRCD_MODULE_EXPORT_DATA +ircd::m::room::server_acl::enable_write +{ + { "name", "ircd.m.room.server_acl.enable.write" }, + { "default", true }, +}; + +/// Coarse control over whether ACL's apply to endpoints considered +/// non-modifying/passive to the room. If false, ACL's are not checked on +/// endpoints which have no visible effects to the federation; this can +/// increase performance. +/// +/// Setting this option to false relaxes the list of endpoints covered by ACL's +/// and departs from the official specification. +/// +/// This option has no effect on the room::server_acl interface itself, it is +/// available for the callsite to check independently before using the iface. +decltype(ircd::m::room::server_acl::enable_read) +IRCD_MODULE_EXPORT_DATA +ircd::m::room::server_acl::enable_read +{ + { "name", "ircd.m.room.server_acl.enable.read" }, + { "default", false }, +}; + +/// Coarse control over whether ACL's are considered for event fetching. If +/// true, events originating from an ACL'ed server will not be fetched, nor +/// will an ACL'ed server be queried by the fetch unit for any event. Note that +/// this cannot fully apply for newer event_id's without hostparts, but the +/// fetch unit may discard such events for an ACL'ed server after receiving. +/// +/// Setting this to true is *stricter* than the official specification, which +/// is vulnerable to "bouncing" around ACL's. +/// (see: https://github.com/maubot/bouncybot) +/// +/// This option has no effect on the room::server_acl interface itself, it is +/// available for the callsite to check independently before using the iface. +decltype(ircd::m::room::server_acl::enable_fetch) +IRCD_MODULE_EXPORT_DATA +ircd::m::room::server_acl::enable_fetch +{ + { "name", "ircd.m.room.server_acl.enable.fetch" }, + { "default", true }, +}; + +/// Coarse control over whether ACL's are considered when this server +/// transmits transactions to the participants in a room. If true, transactions +/// with all contained PDU's and EDU's will not be sent to ACL'ed servers. +/// +/// Setting this to true is *stricter* than the official specification, which +/// leaks all transmissions to ACL'ed servers. +/// +/// This option has no effect on the room::server_acl interface itself, it is +/// available for the callsite to check independently before using the iface. +decltype(ircd::m::room::server_acl::enable_send) +IRCD_MODULE_EXPORT_DATA +ircd::m::room::server_acl::enable_send +{ + { "name", "ircd.m.room.server_acl.enable.send" }, + { "default", true }, +}; + +bool +IRCD_MODULE_EXPORT +ircd::m::room::server_acl::check(const m::room::id &room_id, + const net::hostport &server) +try +{ + const server_acl server_acl + { + room_id + }; + + return server_acl(server); +} +catch(const std::exception &e) +{ + log::critical + { + log, "Failed to check server_acl for '%s' in %s :%s", + string(server), + string_view{room_id}, + e.what() + }; + + return false; +} + +// +// server_acl::server_acl +// + +IRCD_MODULE_EXPORT +ircd::m::room::server_acl::server_acl(const m::room &room, + const event::idx &event_idx) +:room +{ + room +} +,event_idx +{ + !event_idx? + room.get(std::nothrow, "m.room.server_acl", ""): + event_idx +} +{ +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::server_acl::operator()(const net::hostport &server) +const +{ + bool ret; + const auto closure{[this, &server, &ret] + (const json::object &content) + { + // Set the content reference here so only one actual IO is made to + // fetch the m.room.server_acl content for all queries. + const scope_restore this_content + { + this->content, content + }; + + ret = this->check(server); + }}; + + return !view(closure) || ret; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::server_acl::match(const string_view &prop, + const net::hostport &remote) +const +{ + // Spec sez when comparing against the server ACLs, the suspect server's + // port number must not be considered. + const string_view &server + { + net::host(remote) + }; + + return !for_each(prop, [&server] + (const string_view &expression) + { + const globular_match match + { + expression + }; + + // return false to break on match. + return match(server)? false : true; + }); +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::server_acl::has(const string_view &prop, + const string_view &expr) +const +{ + return !for_each(prop, [&expr] + (const string_view &_expr) + { + // false to break on match + return _expr == expr? false : true; + }); +} + +int +IRCD_MODULE_EXPORT +ircd::m::room::server_acl::getbool(const string_view &prop) +const +{ + int ret(-1); + view([&ret, &prop] + (const json::object &object) + { + const string_view &value + { + object[prop] + }; + + if(value == json::literal_true) + ret = 1; + else if(value == json::literal_false) + ret = 0; + }); + + return ret; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::server_acl::has(const string_view &prop) +const +{ + bool ret{false}; + view([&ret, &prop] + (const json::object &object) + { + ret = object.has(prop); + }); + + return ret; +} + +size_t +IRCD_MODULE_EXPORT +ircd::m::room::server_acl::count(const string_view &prop) +const +{ + size_t ret(0); + for_each(prop, [&ret] + (const string_view &) + { + ++ret; + return true; + }); + + return ret; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::server_acl::for_each(const string_view &prop, + const closure_bool &closure) +const +{ + bool ret{true}; + view([&ret, &closure, &prop] + (const json::object &content) + { + const json::array &list + { + content[prop] + }; + + if(!list || json::type(list, std::nothrow) != json::ARRAY) + return; + + for(auto it(begin(list)); it != end(list) && ret; ++it) + { + if(json::type(*it, json::strict, std::nothrow) != json::STRING) + continue; + + if(!closure(json::string(*it))) + ret = false; + } + }); + + return ret; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::server_acl::exists() +const +{ + return content || event_idx; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::server_acl::check(const net::hostport &server) +const +{ + // c2s 13.29.1 rules + + // 1. If there is no m.room.server_acl event in the room state, allow. + if(!exists()) + return true; + + // 2. If the server name is an IP address (v4 or v6) literal, and + // allow_ip_literals is present and false, deny. + if(getbool("allow_ip_literals") == false) + if(rfc3986::valid(std::nothrow, rfc3986::parser::ip_address, net::host(server))) + return false; + + // 3. If the server name matches an entry in the deny list, deny. + if(match("deny", server)) + return false; + + // 4. If the server name matches an entry in the allow list, allow. + if(match("allow", server)) + return true; + + // 5. Otherwise, deny. + return false; +} + +bool +IRCD_MODULE_EXPORT +ircd::m::room::server_acl::view(const view_closure &closure) +const +{ + if(content) + { + closure(content); + return true; + } + + return event_idx && m::get(std::nothrow, event_idx, "content", closure); +} diff --git a/modules/m_rooms.cc b/matrix/rooms.cc similarity index 97% rename from modules/m_rooms.cc rename to matrix/rooms.cc index cad86ab5c..1d14ef0b7 100644 --- a/modules/m_rooms.cc +++ b/matrix/rooms.cc @@ -8,13 +8,8 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix rooms interface; modular components" -}; - decltype(ircd::m::rooms::opts_default) +IRCD_MODULE_EXPORT_DATA ircd::m::rooms::opts_default; bool diff --git a/modules/m_rooms_summary.cc b/matrix/rooms_summary.cc similarity index 99% rename from modules/m_rooms_summary.cc rename to matrix/rooms_summary.cc index e7c34f6e8..a2d55a4cb 100644 --- a/modules/m_rooms_summary.cc +++ b/matrix/rooms_summary.cc @@ -17,12 +17,6 @@ namespace ircd::m::rooms::summary extern hookfn create_public_room; } -ircd::mapi::header -IRCD_MODULE -{ - "Matrix rooms summary" -}; - decltype(ircd::m::rooms::summary::public_room_id) ircd::m::rooms::summary::public_room_id { diff --git a/modules/m_typing.cc b/matrix/typing.cc similarity index 99% rename from modules/m_typing.cc rename to matrix/typing.cc index fb7da9998..0802244e4 100644 --- a/modules/m_typing.cc +++ b/matrix/typing.cc @@ -10,12 +10,6 @@ using namespace ircd; -mapi::header -IRCD_MODULE -{ - "Matrix Typing" -}; - log::log typing_log { diff --git a/modules/m_user.cc b/matrix/user.cc similarity index 96% rename from modules/m_user.cc rename to matrix/user.cc index 58038d899..fe37b1344 100644 --- a/modules/m_user.cc +++ b/matrix/user.cc @@ -10,15 +10,10 @@ namespace ircd::m { + static string_view gen_password_hash(const mutable_buffer &, const string_view &); static room create_user_room(const user::id &, const room::id &, const json::members &contents); } -ircd::mapi::header -IRCD_MODULE -{ - "Matrix user library; modular components." -}; - ircd::m::user IRCD_MODULE_EXPORT ircd::m::create(const m::user::id &user_id, @@ -70,11 +65,6 @@ catch(const std::exception &e) // user::user // -namespace ircd::m -{ - static string_view gen_password_hash(const mutable_buffer &, const string_view &); -} - ircd::m::event::id::buf IRCD_MODULE_EXPORT ircd::m::user::password(const string_view &password) diff --git a/modules/m_user_account_data.cc b/matrix/user_account_data.cc similarity index 97% rename from modules/m_user_account_data.cc rename to matrix/user_account_data.cc index e9445702d..818402a50 100644 --- a/modules/m_user_account_data.cc +++ b/matrix/user_account_data.cc @@ -8,12 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix user account data." -}; - ircd::m::event::id::buf IRCD_MODULE_EXPORT ircd::m::user::account_data::set(const string_view &type, diff --git a/modules/m_user_events.cc b/matrix/user_events.cc similarity index 90% rename from modules/m_user_events.cc rename to matrix/user_events.cc index 48e9b22e0..c90f2b6f7 100644 --- a/modules/m_user_events.cc +++ b/matrix/user_events.cc @@ -8,18 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix events for a user." -}; - -IRCD_MODULE_EXPORT -ircd::m::user::events::events(const m::user &user) -:user{user} -{ -} - size_t IRCD_MODULE_EXPORT ircd::m::user::events::count() diff --git a/modules/m_user_filter.cc b/matrix/user_filter.cc similarity index 98% rename from modules/m_user_filter.cc rename to matrix/user_filter.cc index 897bd5f21..613aec9ef 100644 --- a/modules/m_user_filter.cc +++ b/matrix/user_filter.cc @@ -8,12 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix user filter." -}; - ircd::string_view IRCD_MODULE_EXPORT ircd::m::user::filter::set(const mutable_buffer &buf, diff --git a/modules/m_user_highlight.cc b/matrix/user_highlight.cc similarity index 98% rename from modules/m_user_highlight.cc rename to matrix/user_highlight.cc index e96e46f19..9a7f6ad1d 100644 --- a/modules/m_user_highlight.cc +++ b/matrix/user_highlight.cc @@ -8,13 +8,13 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE +namespace ircd::m { - "Matrix user library; highlight notification support" -}; + static bool user_highlight_match(const string_view &text, const string_view &arg, const size_t &pos); +} decltype(ircd::m::user::highlight::enable_count) +IRCD_MODULE_EXPORT_DATA ircd::m::user::highlight::enable_count { { "name", "ircd.m.user.highlight.enable.count" }, @@ -22,6 +22,7 @@ ircd::m::user::highlight::enable_count }; decltype(ircd::m::user::highlight::match_mxid_full) +IRCD_MODULE_EXPORT_DATA ircd::m::user::highlight::match_mxid_full { { "name", "ircd.m.user.highlight.match.mxid.full" }, @@ -29,6 +30,7 @@ ircd::m::user::highlight::match_mxid_full }; decltype(ircd::m::user::highlight::match_mxid_local_cs) +IRCD_MODULE_EXPORT_DATA ircd::m::user::highlight::match_mxid_local_cs { { "name", "ircd.m.user.highlight.match.mxid.local.cs" }, @@ -36,6 +38,7 @@ ircd::m::user::highlight::match_mxid_local_cs }; decltype(ircd::m::user::highlight::match_mxid_local_cs) +IRCD_MODULE_EXPORT_DATA ircd::m::user::highlight::match_mxid_local_ci { { "name", "ircd.m.user.highlight.match.mxid.local.ci" }, @@ -43,6 +46,7 @@ ircd::m::user::highlight::match_mxid_local_ci }; decltype(ircd::m::user::highlight::match_at_room) +IRCD_MODULE_EXPORT_DATA ircd::m::user::highlight::match_at_room { { "name", "ircd.m.user.highlight.match.at.room" }, @@ -244,11 +248,6 @@ const return false; } -namespace ircd::m -{ - static bool user_highlight_match(const string_view &text, const string_view &arg, const size_t &pos); -} - bool IRCD_MODULE_EXPORT ircd::m::user::highlight::match(const string_view &text, diff --git a/modules/m_user_mitsein.cc b/matrix/user_mitsein.cc similarity index 95% rename from modules/m_user_mitsein.cc rename to matrix/user_mitsein.cc index fee8badb9..ba0527441 100644 --- a/modules/m_user_mitsein.cc +++ b/matrix/user_mitsein.cc @@ -8,18 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix rooms in common between users." -}; - -IRCD_MODULE_EXPORT -ircd::m::user::mitsein::mitsein(const m::user &user) -:user{user} -{ -} - bool IRCD_MODULE_EXPORT ircd::m::user::mitsein::has(const m::user &other, diff --git a/modules/m_user_profile.cc b/matrix/user_profile.cc similarity index 98% rename from modules/m_user_profile.cc rename to matrix/user_profile.cc index e79aaf285..c9f5369f8 100644 --- a/modules/m_user_profile.cc +++ b/matrix/user_profile.cc @@ -13,12 +13,6 @@ namespace ircd::m extern conf::item remote_request_timeout; } -ircd::mapi::header -IRCD_MODULE -{ - "Matrix user profiles." -}; - decltype(ircd::m::remote_request_timeout) ircd::m::remote_request_timeout { diff --git a/modules/m_user_register.cc b/matrix/user_register.cc similarity index 98% rename from modules/m_user_register.cc rename to matrix/user_register.cc index a633b02fa..b6e7172e0 100644 --- a/modules/m_user_register.cc +++ b/matrix/user_register.cc @@ -8,12 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix user register" -}; - ircd::json::object IRCD_MODULE_EXPORT ircd::m::user::registar::operator()(const mutable_buffer &out, diff --git a/modules/m_user_room_account_data.cc b/matrix/user_room_account_data.cc similarity index 97% rename from modules/m_user_room_account_data.cc rename to matrix/user_room_account_data.cc index 8cf1fcdd5..40933217d 100644 --- a/modules/m_user_room_account_data.cc +++ b/matrix/user_room_account_data.cc @@ -8,12 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix user room account data." -}; - ircd::m::event::id::buf IRCD_MODULE_EXPORT ircd::m::user::room_account_data::set(const string_view &user_type, diff --git a/modules/m_user_room_tags.cc b/matrix/user_room_tags.cc similarity index 98% rename from modules/m_user_room_tags.cc rename to matrix/user_room_tags.cc index 2cfda30ff..ee70c118d 100644 --- a/modules/m_user_room_tags.cc +++ b/matrix/user_room_tags.cc @@ -8,12 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix user room tags." -}; - bool IRCD_MODULE_EXPORT ircd::m::user::room_tags::del(const string_view &user_type) diff --git a/modules/m_user_rooms.cc b/matrix/user_rooms.cc similarity index 93% rename from modules/m_user_rooms.cc rename to matrix/user_rooms.cc index 94c792476..387700438 100644 --- a/modules/m_user_rooms.cc +++ b/matrix/user_rooms.cc @@ -8,18 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix rooms for a user." -}; - -IRCD_MODULE_EXPORT -ircd::m::user::rooms::rooms(const m::user &user) -:user_room{user} -{ -} - size_t IRCD_MODULE_EXPORT ircd::m::user::rooms::count() diff --git a/modules/m_users.cc b/matrix/users.cc similarity index 98% rename from modules/m_users.cc rename to matrix/users.cc index 34e6e9acf..7da1d62c7 100644 --- a/modules/m_users.cc +++ b/matrix/users.cc @@ -14,12 +14,6 @@ namespace ircd::m::users static bool for_each_in_host(const opts &, const user::closure_bool &); } -ircd::mapi::header -IRCD_MODULE -{ - "Matrix users interface" -}; - decltype(ircd::m::users::opts_default) ircd::m::users::opts_default; diff --git a/modules/m_user_servers.cc b/matrix/users_servers.cc similarity index 90% rename from modules/m_user_servers.cc rename to matrix/users_servers.cc index 541d776d0..c0e081782 100644 --- a/modules/m_user_servers.cc +++ b/matrix/users_servers.cc @@ -8,18 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -ircd::mapi::header -IRCD_MODULE -{ - "Matrix servers visible to a user from all their rooms." -}; - -IRCD_MODULE_EXPORT -ircd::m::user::servers::servers(const m::user &user) -:user{user} -{ -} - bool IRCD_MODULE_EXPORT ircd::m::user::servers::has(const string_view &server, diff --git a/modules/Makefile.am b/modules/Makefile.am index 3f50296b1..40eb9c33e 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -39,7 +39,6 @@ AM_LDFLAGS = \ moduledir = @moduledir@ -conf_la_SOURCES = conf.cc stats_la_SOURCES = stats.cc net_dns_la_SOURCES = net_dns.cc net_dns_cache.cc net_dns_resolver.cc net_dns_la_CPPFLAGS = -include $(top_srcdir)/include/ircd/asio.h @@ -52,7 +51,6 @@ web_hook_la_SOURCES = web_hook.cc well_known_la_SOURCES = well_known.cc module_LTLIBRARIES = \ - conf.la \ stats.la \ net_dns.la \ console.la \ @@ -81,135 +79,62 @@ endif IMAGEMAGICK m_moduledir = @moduledir@ -m_node_la_SOURCES = m_node.cc -m_keys_la_SOURCES = m_keys.cc -m_event_la_SOURCES = m_event.cc -m_feds_la_SOURCES = m_feds.cc -m_fetch_la_SOURCES = m_fetch.cc - -m_room_la_SOURCES = m_room.cc -m_room_events_la_SOURCES = m_room_events.cc -m_room_auth_la_SOURCES = m_room_auth.cc -m_room_head_la_SOURCES = m_room_head.cc -m_room_create_la_SOURCES = m_room_create.cc -m_room_member_la_SOURCES = m_room_member.cc -m_room_join_la_SOURCES = m_room_join.cc -m_room_leave_la_SOURCES = m_room_leave.cc -m_room_join_rules_la_SOURCES = m_room_join_rules.cc -m_room_history_visibility_la_SOURCES = m_room_history_visibility.cc -m_room_canonical_alias_la_SOURCES = m_room_canonical_alias.cc -m_room_aliases_la_SOURCES = m_room_aliases.cc -m_room_message_la_SOURCES = m_room_message.cc -m_room_power_levels_la_SOURCES = m_room_power_levels.cc -m_room_server_acl_la_SOURCES = m_room_server_acl.cc -m_room_third_party_invite_la_SOURCES = m_room_third_party_invite.cc -m_room_redaction_la_SOURCES = m_room_redaction.cc -m_room_bootstrap_la_SOURCES = m_room_bootstrap.cc -m_room_name_la_SOURCES = m_room_name.cc - -m_user_la_SOURCES = m_user.cc -m_user_events_la_SOURCES = m_user_events.cc -m_user_rooms_la_SOURCES = m_user_rooms.cc -m_user_filter_la_SOURCES = m_user_filter.cc -m_user_register_la_SOURCES = m_user_register.cc -m_user_mitsein_la_SOURCES = m_user_mitsein.cc -m_user_servers_la_SOURCES = m_user_servers.cc -m_user_highlight_la_SOURCES = m_user_highlight.cc m_user_highlight_auth.cc -m_user_profile_la_SOURCES = m_user_profile.cc -m_user_account_data_la_SOURCES = m_user_account_data.cc -m_user_room_account_data_la_SOURCES = m_user_room_account_data.cc -m_user_room_tags_la_SOURCES = m_user_room_tags.cc - -m_events_la_SOURCES = m_events.cc -m_rooms_la_SOURCES = m_rooms.cc -m_rooms_summary_la_SOURCES = m_rooms_summary.cc -m_users_la_SOURCES = m_users.cc - -m_presence_la_SOURCES = m_presence.cc -m_receipt_la_SOURCES = m_receipt.cc -m_typing_la_SOURCES = m_typing.cc -m_device_list_update_la_SOURCES = m_device_list_update.cc -m_device_la_SOURCES = m_device.cc -m_direct_la_SOURCES = m_direct.cc -m_direct_to_device_la_SOURCES = m_direct_to_device.cc m_breadcrumb_rooms_la_SOURCES = m_breadcrumb_rooms.cc -m_ignored_user_list_la_SOURCES = m_ignored_user_list.cc m_command_la_SOURCES = m_command.cc m_control_la_SOURCES = m_control.cc -m_create_la_SOURCES = m_create.cc -m_profile_la_SOURCES = m_profile.cc -m_noop_la_SOURCES = m_noop.cc - -m_event_append_la_SOURCES = m_event_append.cc -m_event_horizon_la_SOURCES = m_event_pretty.cc -m_event_pretty_la_SOURCES = m_event_horizon.cc - -m_init_backfill_la_SOURCES = m_init_backfill.cc +m_device_la_SOURCES = m_device.cc +m_device_list_update_la_SOURCES = m_device_list_update.cc +m_direct_la_SOURCES = m_direct.cc +m_direct_to_device_la_SOURCES = m_direct_to_device.cc +m_ignored_user_list_la_SOURCES = m_ignored_user_list.cc m_listen_la_SOURCES = m_listen.cc - +m_noop_la_SOURCES = m_noop.cc +m_presence_la_SOURCES = m_presence.cc +m_profile_la_SOURCES = m_profile.cc +m_receipt_la_SOURCES = m_receipt.cc +m_room_aliases_la_SOURCES = m_room_aliases.cc +m_room_canonical_alias_la_SOURCES = m_room_canonical_alias.cc +m_room_create_la_SOURCES = m_room_create.cc +m_room_history_visibility_la_SOURCES = m_room_history_visibility.cc +m_room_join_rules_la_SOURCES = m_room_join_rules.cc +m_room_member_la_SOURCES = m_room_member.cc +m_room_message_la_SOURCES = m_room_message.cc +m_room_name_la_SOURCES = m_room_name.cc +m_room_power_levels_la_SOURCES = m_room_power_levels.cc +m_room_redaction_la_SOURCES = m_room_redaction.cc +m_room_server_acl_la_SOURCES = m_room_server_acl.cc +m_room_third_party_invite_la_SOURCES = m_room_third_party_invite.cc +m_user_highlight_auth_la_SOURCES = m_user_highlight_auth.cc m_vm_la_SOURCES = m_vm.cc m_vm_fetch_la_SOURCES = m_vm_fetch.cc m_module_LTLIBRARIES = \ - m_noop.la \ - m_event.la \ - m_event_append.la \ - m_event_horizon.la \ - m_event_pretty.la \ - m_user.la \ - m_user_events.la \ - m_user_rooms.la \ - m_user_filter.la \ - m_user_register.la \ - m_user_mitsein.la \ - m_user_servers.la \ - m_user_highlight.la \ - m_user_profile.la \ - m_user_account_data.la \ - m_user_room_account_data.la \ - m_user_room_tags.la \ - m_node.la \ - m_keys.la \ - m_feds.la \ - m_fetch.la \ + m_breadcrumb_rooms.la \ m_command.la \ m_control.la \ - m_create.la \ - m_profile.la \ m_device.la \ - m_direct.la \ - m_typing.la \ - m_receipt.la \ - m_presence.la \ - m_direct_to_device.la \ m_device_list_update.la \ + m_direct.la \ + m_direct_to_device.la \ m_ignored_user_list.la \ - m_breadcrumb_rooms.la \ - m_events.la \ - m_rooms.la \ - m_rooms_summary.la \ - m_room.la \ - m_room_events.la \ - m_room_auth.la \ - m_room_head.la \ - m_room_create.la \ - m_room_member.la \ - m_room_join.la \ - m_room_leave.la \ - m_room_join_rules.la \ - m_room_history_visibility.la \ - m_room_canonical_alias.la \ + m_listen.la \ + m_noop.la \ + m_presence.la \ + m_profile.la \ + m_receipt.la \ m_room_aliases.la \ + m_room_canonical_alias.la \ + m_room_create.la \ + m_room_history_visibility.la \ + m_room_join_rules.la \ + m_room_member.la \ m_room_message.la \ + m_room_name.la \ m_room_power_levels.la \ - m_room_third_party_invite.la \ m_room_redaction.la \ m_room_server_acl.la \ - m_room_bootstrap.la \ - m_room_name.la \ - m_init_backfill.la \ - m_listen.la \ - m_users.la \ + m_room_third_party_invite.la \ + m_user_highlight_auth.la \ m_vm.la \ m_vm_fetch.la \ ### diff --git a/modules/m_breadcrumb_rooms.cc b/modules/m_breadcrumb_rooms.cc index ec81ca5eb..e799d2e84 100644 --- a/modules/m_breadcrumb_rooms.cc +++ b/modules/m_breadcrumb_rooms.cc @@ -129,69 +129,3 @@ ircd::m::handle_breadcrumb_rooms_focus_out(const event &event, at<"sender"_>(event), }; } - -ircd::m::event::id::buf -IRCD_MODULE_EXPORT -ircd::m::breadcrumb_rooms::set(const json::array &rooms) -const -{ - const json::strung object - { - json::members - { - { "rooms", rooms } - } - }; - - return account_data.set("im.vector.riot.breadcrumb_rooms", object); -} - -bool -IRCD_MODULE_EXPORT -ircd::m::breadcrumb_rooms::for_each(const closure_bool &closure) -const -{ - bool ret{true}; - get(std::nothrow, [&closure, &ret] - (const json::array &rooms) - { - for(const json::string &room : rooms) - if(!closure(room)) - { - ret = false; - break; - } - }); - - return ret; -} - -void -IRCD_MODULE_EXPORT -ircd::m::breadcrumb_rooms::get(const closure &closure) -const -{ - if(!get(std::nothrow, closure)) - throw m::NOT_FOUND - { - "User has no breadcrumb_rooms set in their account_data." - }; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::breadcrumb_rooms::get(std::nothrow_t, - const closure &closure) -const -{ - return account_data.get(std::nothrow, "im.vector.riot.breadcrumb_rooms", [&closure] - (const string_view &key, const json::object &object) - { - const json::array &rooms - { - object["rooms"] - }; - - closure(rooms); - }); -} diff --git a/modules/m_device.cc b/modules/m_device.cc index 997154cd2..83a4c8e95 100644 --- a/modules/m_device.cc +++ b/modules/m_device.cc @@ -20,136 +20,6 @@ IRCD_MODULE "Matrix device library; modular components." }; -std::map -IRCD_MODULE_EXPORT -ircd::m::device::count_one_time_keys(const user &user, - const string_view &device_id) -{ - std::map ret; - for_each(user, device_id, [&ret] - (const string_view &type) - { - if(!startswith(type, "one_time_key|")) - return true; - - const auto &[prefix, ident] - { - split(type, '|') - }; - - const auto &[algorithm, name] - { - split(ident, ':') - }; - - assert(prefix == "one_time_key"); - assert(!empty(algorithm)); - assert(!empty(ident)); - assert(!empty(name)); - - auto it(ret.lower_bound(algorithm)); - if(it == end(ret) || it->first != algorithm) - it = ret.emplace_hint(it, algorithm, 0L); - - auto &count(it->second); - ++count; - return true; - }); - - return ret; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::device::set(const m::user &user, - const device &device) -{ - const user::room user_room{user}; - const string_view &device_id - { - json::at<"device_id"_>(device) - }; - - json::for_each(device, [&user, &user_room, &device_id] - (const auto &prop, auto &&val) - { - if(!json::defined(json::value(val))) - return; - - char buf[m::event::TYPE_MAX_SIZE]; - const string_view type{fmt::sprintf - { - buf, "ircd.device.%s", prop - }}; - - m::send(user_room, user, type, device_id, json::members - { - { "", val } - }); - }); - - return true; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::device::set(const m::user &user, - const string_view &id, - const string_view &prop, - const string_view &val) -{ - char buf[m::event::TYPE_MAX_SIZE]; - const string_view type{fmt::sprintf - { - buf, "ircd.device.%s", prop - }}; - - const user::room user_room{user}; - m::send(user_room, user, type, id, json::members - { - { "", val } - }); - - return true; -} - -/// To delete a device we iterate the user's room state for all types matching -/// ircd.device.* (and ircd.device) which have a state_key of the device_id. -/// Those events are redacted which removes them from appearing in the state. -bool -IRCD_MODULE_EXPORT -ircd::m::device::del(const m::user &user, - const string_view &id) -{ - const user::room user_room{user}; - const room::state state{user_room}; - const room::state::type_prefix type - { - "ircd.device." - }; - - state.for_each(type, [&user, &id, &user_room, &state] - (const string_view &type, const string_view &, const event::idx &) - { - const auto event_idx - { - state.get(std::nothrow, type, id) - }; - - const auto event_id - { - m::event_id(event_idx, std::nothrow) - }; - - if(event_id) - m::redact(user_room, user, event_id, "deleted"); - - return true; - }); - - return true; -} - /// Deletes the access_token associated with a device when the device /// (specifically the access_token_id property of that device) is deleted. decltype(ircd::m::_access_token_delete_hook) @@ -189,174 +59,3 @@ ircd::m::_access_token_delete(const m::event &event, m::redact(m::user::tokens, at<"sender"_>(event), token_event_id, "device deleted"); }); }; - -bool -IRCD_MODULE_EXPORT -ircd::m::device::has(const m::user &user, - const string_view &id) -{ - const user::room user_room{user}; - const room::state state{user_room}; - const room::state::type_prefix type - { - "ircd.device." - }; - - bool ret(false); - state.for_each(type, [&state, &id, &ret] - (const string_view &type, const string_view &, const event::idx &) - { - ret = state.has(type, id); - return !ret; - }); - - return ret; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::device::has(const m::user &user, - const string_view &id, - const string_view &prop) -{ - bool ret{false}; - get(std::nothrow, user, id, prop, [&ret] - (const string_view &value) - { - ret = !empty(value); - }); - - return ret; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::device::get(std::nothrow_t, - const m::user &user, - const string_view &id, - const string_view &prop, - const closure &closure) -{ - char buf[m::event::TYPE_MAX_SIZE]; - const string_view type{fmt::sprintf - { - buf, "ircd.device.%s", prop - }}; - - const m::user::room user_room{user}; - const m::room::state state{user_room}; - const auto event_idx - { - state.get(std::nothrow, type, id) - }; - - return m::get(std::nothrow, event_idx, "content", [&closure] - (const json::object &content) - { - const string_view &value - { - content.get("") - }; - - closure(value); - }); -} - -bool -IRCD_MODULE_EXPORT -ircd::m::device::for_each(const m::user &user, - const string_view &device_id, - const closure_bool &closure) -{ - const m::user::room user_room{user}; - const m::room::state state{user_room}; - const room::state::type_prefix type - { - "ircd.device." - }; - - return state.for_each(type, [&state, &device_id, &closure] - (const string_view &type, const string_view &, const event::idx &) - { - const string_view &prop - { - lstrip(type, "ircd.device.") - }; - - return state.has(type, device_id)? - closure(prop): - true; - }); -} - -bool -IRCD_MODULE_EXPORT -ircd::m::device::for_each(const m::user &user, - const closure_bool &closure) -{ - const m::user::room user_room - { - user - }; - - const m::room::state state - { - user_room - }; - - return state.for_each("ircd.device.device_id", [&closure] - (const string_view &, const string_view &state_key, const event::idx &) - { - return closure(state_key); - }); -} - -ircd::m::device::id::buf -IRCD_MODULE_EXPORT -ircd::m::device::access_token_to_id(const string_view &token) -{ - id::buf ret; - access_token_to_id(token, [&ret] - (const string_view &device_id) - { - ret = device_id; - }); - - return ret; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::device::access_token_to_id(const string_view &token, - const closure &closure) -{ - const m::room::state &state{m::user::tokens}; - const m::event::idx &event_idx - { - state.get(std::nothrow, "ircd.access_token", token) - }; - - bool ret{false}; - const auto device_id{[&closure, &ret] - (const json::object &content) - { - const json::string &device_id - { - content["device_id"] - }; - - if(likely(device_id)) - { - closure(device_id); - ret = true; - } - }}; - - if(!event_idx) - return ret; - - if(!m::get(std::nothrow, event_idx, "content", device_id)) - return ret; - - return ret; -} diff --git a/modules/m_device_list_update.cc b/modules/m_device_list_update.cc index 3445e15c3..54e59f7c9 100644 --- a/modules/m_device_list_update.cc +++ b/modules/m_device_list_update.cc @@ -10,16 +10,16 @@ using namespace ircd; +static void +handle_edu_m_device_list_update(const m::event &, + m::vm::eval &); + mapi::header IRCD_MODULE { "Matrix Device List Update" }; -static void -handle_edu_m_device_list_update(const m::event &, - m::vm::eval &); - m::hookfn _m_device_list_update_eval { diff --git a/modules/m_event.cc b/modules/m_event.cc deleted file mode 100644 index 9f86fc428..000000000 --- a/modules/m_event.cc +++ /dev/null @@ -1,20 +0,0 @@ -// Matrix Construct -// -// Copyright (C) Matrix Construct Developers, Authors & Contributors -// Copyright (C) 2016-2019 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. - -// NOTE: !!! -// Definitions re currently split between libircd and modules until the API -// and dependency graph has stabilized. Eventually most/all of ircd::m:: -// should migrate out of libircd into modules. - -ircd::mapi::header -IRCD_MODULE -{ - "Matrix event library" -}; diff --git a/modules/m_ignored_user_list.cc b/modules/m_ignored_user_list.cc index d8d1c5958..b302734ad 100644 --- a/modules/m_ignored_user_list.cc +++ b/modules/m_ignored_user_list.cc @@ -19,20 +19,6 @@ IRCD_MODULE "14.24 :Ignoring Users" }; -conf::item -enforce_invites -{ - { "name", "ircd.m.ignored_user_list.enforce.invites" }, - { "default", true } -}; - -conf::item -enforce_events -{ - { "name", "ircd.m.ignored_user_list.enforce.events" }, - { "default", false } -}; - /* m::hookfn _m_ignored_user_list @@ -96,65 +82,3 @@ handle_m_ignored_user(const m::event &event, string_view{user_id}, }; } - -bool -IRCD_MODULE_EXPORT -ircd::m::user::ignores::has(const m::user::id &other) -const -{ - return !for_each([&other] - (const m::user::id &user_id, const json::object &) - { - return user_id != other; - }); -} - -bool -IRCD_MODULE_EXPORT -ircd::m::user::ignores::for_each(const closure_bool &closure) -const try -{ - const m::user::account_data account_data - { - user - }; - - bool ret{true}; - account_data.get(std::nothrow, "m.ignored_user_list", [&closure, &ret] - (const string_view &key, const json::object &content) - { - const json::object &ignored_users - { - content.get("ignored_users") - }; - - for(const auto &[user_id, object] : ignored_users) - if(!(ret = closure(user_id, object))) - return; - }); - - return ret; -} -catch(const std::exception &e) -{ - log::derror - { - m::log, "Error in ignore list for %s", - string_view{user.user_id} - }; - - return true; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::user::ignores::enforce(const string_view &type) -{ - if(type == "events") - return bool(enforce_events); - - if(type == "invites") - return bool(enforce_invites); - - return false; -} diff --git a/modules/m_presence.cc b/modules/m_presence.cc index bddd3fdbe..cca3f4cbe 100644 --- a/modules/m_presence.cc +++ b/modules/m_presence.cc @@ -315,92 +315,3 @@ catch(const std::exception &e) e.what(), }; } - -bool -IRCD_MODULE_EXPORT -ircd::m::presence::get(const std::nothrow_t, - const m::user &user, - const m::presence::closure_event &closure, - const m::event::fetch::opts *const &fopts_p) -{ - const m::event::idx event_idx - { - m::presence::get(std::nothrow, user) - }; - - if(!event_idx) - return false; - - const auto &fopts - { - fopts_p? *fopts_p : event::fetch::default_opts - }; - - const m::event::fetch event - { - event_idx, std::nothrow, fopts - }; - - if(event.valid) - closure(event); - - return event.valid; -} - -m::event::idx -IRCD_MODULE_EXPORT -ircd::m::presence::get(const std::nothrow_t, - const m::user &user) -{ - const m::user::room user_room - { - user - }; - - const m::room::state state - { - user_room - }; - - return state.get(std::nothrow, "ircd.presence", ""); -} - -m::event::id::buf -IRCD_MODULE_EXPORT -ircd::m::presence::set(const m::presence &content) -{ - const m::user user - { - json::at<"user_id"_>(content) - }; - - //TODO: ABA - if(!exists(user)) - create(user.user_id); - - m::vm::copts copts; - const m::user::room user_room - { - user, &copts - }; - - //TODO: ABA - return send(user_room, user.user_id, "ircd.presence", "", json::strung{content}); -} - -const string_view -valid_states[] -{ - "online", "offline", "unavailable", -}; - -bool -IRCD_MODULE_EXPORT -ircd::m::presence::valid_state(const string_view &state) -{ - return std::any_of(begin(valid_states), end(valid_states), [&state] - (const string_view &valid) - { - return state == valid; - }); -} diff --git a/modules/m_receipt.cc b/modules/m_receipt.cc index dbb94431b..9eeef93c5 100644 --- a/modules/m_receipt.cc +++ b/modules/m_receipt.cc @@ -8,24 +8,6 @@ // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. -/// There are three principal component sections in this unit: -/// -/// ---------------------------------- _ -/// | 1. Incoming federation EDU hook | | -/// ---------------------------------- | -/// ---------------------------------- | -/// | 2. ircd::m::receipt API | | -/// ---------------------------------- | -/// ---------------------------------- | -/// | 3. Outgoing federation EDU hook | V -/// ---------------------------------- -/// -/// This unit parses and accepts m.receipt EDU's from the federation (1); then -/// it calls the m::receipt API (2) which generates internal PDU's sent to -/// user rooms. Hooks on these events sent to user rooms (3) turn the events -/// into federation EDU's for broadcast (for local users). Note that there are -/// other reactives for these internal events in client/sync, etc. - using namespace ircd; static void handle_ircd_read(const m::event &, m::vm::eval &); @@ -47,12 +29,6 @@ IRCD_MODULE "Matrix Receipts" }; -log::log -receipt_log -{ - "m.receipt" -}; - // // EDU handler. // @@ -98,7 +74,7 @@ handle_edu_m_receipt(const m::event &event, { log::dwarning { - receipt_log, "Ignoring m.receipt from '%s' in %s :denied by m.room.server_acl.", + m::receipt::log, "Ignoring m.receipt from '%s' in %s :denied by m.room.server_acl.", json::get<"origin"_>(event), string_view{room_id}, }; @@ -125,7 +101,7 @@ handle_m_receipt(const m::event &event, log::dwarning { - receipt_log, "Unhandled m.receipt type '%s' to room '%s'", + m::receipt::log, "Unhandled m.receipt type '%s' to room '%s'", type, string_view{room_id} }; @@ -144,7 +120,7 @@ handle_m_receipt_m_read(const m::event &event, { log::dwarning { - receipt_log, "Ignoring m.receipt m.read from '%s' in %s for alien %s.", + m::receipt::log, "Ignoring m.receipt m.read from '%s' in %s for alien %s.", json::get<"origin"_>(event), string_view{room_id}, string_view{user_id}, @@ -180,7 +156,7 @@ handle_m_receipt_m_read(const m::room::id &room_id, { log::derror { - receipt_log, "Failed to handle m.receipt m.read for %s in %s for '%s' :%s", + m::receipt::log, "Failed to handle m.receipt m.read for %s in %s for '%s' :%s", string_view{user_id}, string_view{room_id}, string_view{event_id}, @@ -211,7 +187,7 @@ try { log::dwarning { - receipt_log, "Ignoring m.receipt m.read for unknown %s in %s for %s", + m::receipt::log, "Ignoring m.receipt m.read for unknown %s in %s for %s", string_view{user_id}, string_view{room_id}, string_view{event_id} @@ -229,7 +205,7 @@ catch(const std::exception &e) { log::derror { - receipt_log, "Failed to save m.receipt m.read for %s in %s for %s :%s", + m::receipt::log, "Failed to save m.receipt m.read for %s in %s for %s :%s", string_view{user_id}, string_view{room_id}, string_view{event_id}, @@ -237,188 +213,6 @@ catch(const std::exception &e) }; } -// -// m::receipt API -> Internal -// - -m::event::id::buf -IRCD_MODULE_EXPORT -ircd::m::receipt::read(const m::room::id &room_id, - const m::user::id &user_id, - const m::event::id &event_id, - const json::object &options) -{ - const m::user::room user_room - { - user_id - }; - - const auto evid - { - send(user_room, user_id, "ircd.read", room_id, - { - { "event_id", event_id }, - { "ts", options.get("ts", ircd::time()) }, - { "m.hidden", options.get("m.hidden", false) }, - }) - }; - - log::info - { - receipt_log, "%s read by %s in %s options:%s", - string_view{event_id}, - string_view{user_id}, - string_view{room_id}, - string_view{options}, - }; - - return evid; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::receipt::get(const m::room::id &room_id, - const m::user::id &user_id, - const m::event::id::closure &closure) -{ - const m::user::room user_room - { - user_id - }; - - const auto event_idx - { - user_room.get(std::nothrow, "ircd.read", room_id) - }; - - return m::get(std::nothrow, event_idx, "content", [&closure] - (const json::object &content) - { - const json::string &event_id - { - content["event_id"] - }; - - closure(event_id); - }); -} - - -/// Does the user wish to not send receipts for events sent by its specific -/// sender? -bool -IRCD_MODULE_EXPORT -ircd::m::receipt::ignoring(const m::user &user, - const m::event::id &event_id) -{ - bool ret{false}; - m::get(std::nothrow, event_id, "sender", [&ret, &user] - (const string_view &sender) - { - const m::user::room user_room{user}; - ret = user_room.has("ircd.read.ignore", sender); - }); - - return ret; -} - -/// Does the user wish to not send receipts for events for this entire room? -bool -IRCD_MODULE_EXPORT -ircd::m::receipt::ignoring(const m::user &user, - const m::room::id &room_id) -{ - const m::user::room user_room{user}; - return user_room.has("ircd.read.ignore", room_id); -} - -bool -IRCD_MODULE_EXPORT -ircd::m::receipt::freshest(const m::room::id &room_id, - const m::user::id &user_id, - const m::event::id &event_id) -try -{ - const m::user::room user_room - { - user_id - }; - - bool ret{true}; - user_room.get("ircd.read", room_id, [&ret, &event_id] - (const m::event &event) - { - const auto &content - { - at<"content"_>(event) - }; - - const m::event::id &previous_id - { - unquote(content.get("event_id")) - }; - - if(event_id == previous_id) - { - ret = false; - return; - } - - const m::event::idx &previous_idx - { - index(previous_id) - }; - - const m::event::idx &event_idx - { - index(event_id) - }; - - ret = event_idx > previous_idx; - }); - - return ret; -} -catch(const std::exception &e) -{ - log::derror - { - receipt_log, "Freshness of receipt in %s from %s for %s :%s", - string_view{room_id}, - string_view{user_id}, - string_view{event_id}, - e.what() - }; - - return true; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::receipt::exists(const m::room::id &room_id, - const m::user::id &user_id, - const m::event::id &event_id) -{ - const m::user::room user_room - { - user_id - }; - - bool ret{false}; - user_room.get(std::nothrow, "ircd.read", room_id, [&ret, &event_id] - (const m::event &event) - { - const auto &content - { - at<"content"_>(event) - }; - - ret = unquote(content.get("event_id")) == event_id; - }); - - return ret; -} - // // Internal -> Federation // @@ -482,7 +276,7 @@ catch(const std::exception &e) { log::error { - receipt_log, "Implicit receipt hook for %s :%s", + m::receipt::log, "Implicit receipt hook for %s :%s", string_view{event.event_id}, e.what(), }; @@ -607,7 +401,7 @@ catch(const std::exception &e) { log::error { - receipt_log, "ircd.read hook on %s for federation broadcast :%s", + m::receipt::log, "ircd.read hook on %s for federation broadcast :%s", string_view{event.event_id}, e.what(), }; diff --git a/modules/m_room_aliases.cc b/modules/m_room_aliases.cc index a297ba19a..b94fc2e4b 100644 --- a/modules/m_room_aliases.cc +++ b/modules/m_room_aliases.cc @@ -10,8 +10,6 @@ namespace ircd::m { - extern conf::item alias_fetch_timeout; - extern conf::item alias_cache_ttl; extern const room::id::buf alias_room_id; extern const room alias_room; @@ -42,20 +40,6 @@ ircd::m::alias_room alias_room_id }; -decltype(ircd::m::alias_cache_ttl) -ircd::m::alias_cache_ttl -{ - { "name", "ircd.m.room.aliases.cache.ttl" }, - { "default", 604800L }, -}; - -decltype(ircd::m::alias_fetch_timeout) -ircd::m::alias_fetch_timeout -{ - { "name", "ircd.m.room.aliases.fetch.timeout" }, - { "default", 10L }, -}; - // // create the alias room as an effect of !ircd created on bootstrap // @@ -174,425 +158,3 @@ ircd::m::auth_room_aliases(const event &event, // c. Otherwise, allow data.allow = true; } - -// -// m::room::aliases -// - -bool -IRCD_MODULE_EXPORT -ircd::m::room::aliases::for_each(const m::room &room, - const string_view &server, - const closure_bool &closure) -{ - const room::state state - { - room - }; - - assert(server); - const event::idx &event_idx - { - state.get(std::nothrow, "m.room.aliases", server) - }; - - if(!event_idx) - return true; - - bool ret{true}; - m::get(std::nothrow, event_idx, "content", [&closure, &ret] - (const json::object &content) - { - const json::array &aliases - { - content["aliases"] - }; - - for(auto it(begin(aliases)); it != end(aliases) && ret; ++it) - { - const json::string &alias(*it); - if(!valid(m::id::ROOM_ALIAS, alias)) - continue; - - if(!closure(alias)) - ret = false; - } - }); - - return ret; -} - -// -// m::room::aliases::cache -// - -bool -IRCD_MODULE_EXPORT -ircd::m::room::aliases::cache::del(const alias &alias) -{ - char buf[m::id::room_alias::buf::SIZE]; - const string_view &key - { - make_key(buf, alias) - }; - - const auto &event_idx - { - alias_room.get(std::nothrow, "ircd.room.alias", key) - }; - - if(!event_idx) - return false; - - const auto event_id - { - m::event_id(event_idx, std::nothrow) - }; - - if(!event_id) - return false; - - const auto ret - { - redact(alias_room, m::me.user_id, event_id, "deleted") - }; - - return true; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::room::aliases::cache::set(const alias &alias, - const id &id) -{ - char buf[m::id::room_alias::buf::SIZE]; - const string_view &key - { - make_key(buf, alias) - }; - - const auto ret - { - send(alias_room, m::me.user_id, "ircd.room.alias", key, - { - { "room_id", id } - }) - }; - - return true; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::room::aliases::cache::get(std::nothrow_t, - const alias &alias, - const id::closure &closure) -{ - m::event::idx event_idx - { - getidx(alias) - }; - - if(!event_idx) - { - if(my_host(alias.host())) - return false; - - if(!fetch(std::nothrow, alias, alias.host())) - return false; - - event_idx = getidx(alias); - } - - const bool expired - { - !my_host(alias.host()) && cache::expired(event_idx) - }; - - if(expired) - { - log::dwarning - { - log, "Cached alias %s expired age:%ld ttl:%ld", - string_view{alias}, - cache::age(event_idx).count(), - milliseconds(seconds(alias_cache_ttl)).count(), - }; - - fetch(std::nothrow, alias, alias.host()); - event_idx = getidx(alias); - } - - if(!event_idx) - return false; - - bool ret{false}; - m::get(std::nothrow, event_idx, "content", [&closure, &ret] - (const json::object &content) - { - const json::string &room_id - { - content.get("room_id") - }; - - if(!empty(room_id)) - { - ret = true; - closure(room_id); - } - }); - - return ret; -} - -namespace ircd::m -{ - thread_local char room_aliases_cache_fetch_hpbuf[384]; -} - -void -IRCD_MODULE_EXPORT -ircd::m::room::aliases::cache::fetch(const alias &alias, - const net::hostport &hp) -try -{ - const unique_buffer buf - { - 16_KiB - }; - - m::v1::query::opts opts; - opts.remote = hp; - opts.dynamic = true; - - m::v1::query::directory request - { - alias, buf, std::move(opts) - }; - - request.wait(seconds(alias_fetch_timeout)); - const http::code &code - { - request.get() - }; - - const json::object response - { - request - }; - - if(!response.has("room_id")) - throw m::NOT_FOUND - { - "Server '%s' does not know room_id for %s", - string(room_aliases_cache_fetch_hpbuf, hp), - string_view{alias}, - }; - - const m::room::id &room_id - { - unquote(response["room_id"]) - }; - - set(alias, room_id); -} -catch(const ctx::timeout &e) -{ - throw m::error - { - http::GATEWAY_TIMEOUT, "M_ROOM_ALIAS_TIMEOUT", - "Server '%s' did not respond with a room_id for %s in time", - string(room_aliases_cache_fetch_hpbuf, hp), - string_view{alias}, - }; -} -catch(const server::unavailable &e) -{ - throw m::error - { - http::BAD_GATEWAY, "M_ROOM_ALIAS_UNAVAILABLE", - "Server '%s' is not available to query a room_id for %s", - string(room_aliases_cache_fetch_hpbuf, hp), - string_view{alias}, - }; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::room::aliases::cache::for_each(const string_view &server, - const closure_bool &closure) -{ - const m::room::state state - { - alias_room - }; - - bool ret{true}; - const m::room::state::closure_bool reclosure{[&server, &closure, &ret] - (const string_view &type, const string_view &state_key, const m::event::idx &event_idx) - { - thread_local char swapbuf[m::id::room_alias::buf::SIZE]; - const alias &alias - { - m::id::unswap(state_key, swapbuf) - }; - - if(server && alias.host() != server) - return false; - - if(expired(event_idx)) - return true; - - m::get(std::nothrow, event_idx, "content", [&closure, &ret, &alias] - (const json::object &content) - { - const json::string &room_id - { - content.get("room_id") - }; - - if(!empty(room_id)) - ret = closure(alias, room_id); - }); - - return ret; - }}; - - state.for_each("ircd.room.alias", server, reclosure); - return ret; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::room::aliases::cache::has(const alias &alias) -{ - const auto &event_idx - { - getidx(alias) - }; - - if(!event_idx) - return false; - - if(expired(event_idx)) - return false; - - bool ret{false}; - m::get(std::nothrow, event_idx, "content", [&ret] - (const json::object &content) - { - const json::string &room_id - { - content.get("room_id") - }; - - ret = !empty(room_id); - }); - - return ret; -} - -ircd::system_point -IRCD_MODULE_EXPORT -ircd::m::room::aliases::cache::expires(const alias &alias) -{ - const auto event_idx - { - getidx(alias) - }; - - if(!event_idx) - return system_point::min(); - - const milliseconds age - { - cache::age(event_idx) - }; - - const seconds ttl - { - alias_cache_ttl - }; - - return now() + (ttl - age); -} - -bool -IRCD_MODULE_EXPORT -ircd::m::room::aliases::cache::expired(const event::idx &event_idx) -{ - const milliseconds age - { - cache::age(event_idx) - }; - - const seconds ttl - { - alias_cache_ttl - }; - - return age > ttl; -} - -ircd::milliseconds -IRCD_MODULE_EXPORT -ircd::m::room::aliases::cache::age(const event::idx &event_idx) -{ - time_t ts; - if(!m::get(event_idx, "origin_server_ts", ts)) - return milliseconds::max(); - - const time_t now - { - ircd::time() - }; - - return milliseconds - { - now - ts - }; -} - -ircd::m::event::idx -IRCD_MODULE_EXPORT -ircd::m::room::aliases::cache::getidx(const alias &alias) -{ - thread_local char swapbuf[m::id::room_alias::buf::SIZE]; - const string_view &swapped - { - alias.swap(swapbuf) - }; - - char buf[m::id::room_alias::buf::SIZE]; - const string_view &key - { - tolower(buf, swapped) - }; - - const auto &event_idx - { - alias_room.get(std::nothrow, "ircd.room.alias", key) - }; - - return event_idx; -} - -ircd::string_view -IRCD_MODULE_EXPORT -ircd::m::room::aliases::cache::make_key(const mutable_buffer &out, - const alias &alias) -{ - - thread_local char swapbuf[m::id::room_alias::buf::SIZE] alignas(16); - const string_view &swapped - { - alias.swap(swapbuf) - }; - - const string_view &key - { - tolower(out, swapped) - }; - - return key; -} diff --git a/modules/m_room_history_visibility.cc b/modules/m_room_history_visibility.cc index 68302de1b..5f201828c 100644 --- a/modules/m_room_history_visibility.cc +++ b/modules/m_room_history_visibility.cc @@ -10,9 +10,6 @@ namespace ircd::m { - static bool visible_to_node(const room &, const string_view &node_id, const event &); - static bool visible_to_user(const room &, const string_view &history_visibility, const m::user::id &, const event &); - static void changed_history_visibility(const event &, vm::eval &); extern hookfn changed_history_visibility_hookfn; } @@ -46,138 +43,3 @@ ircd::m::changed_history_visibility(const event &event, string_view{event.event_id}, }; } - -bool -IRCD_MODULE_EXPORT -ircd::m::visible(const m::event &event, - const string_view &mxid) -{ - const m::room room - { - at<"room_id"_>(event), event.event_id - }; - - const m::room::state state - { - room - }; - - const event::idx visibility_event_idx - { - state.get(std::nothrow, "m.room.history_visibility", "") - }; - - char buf[32]; - string_view history_visibility{"shared"}; - m::get(std::nothrow, visibility_event_idx, "content", [&buf, &history_visibility] - (const json::object &content) - { - const json::string &_history_visibility - { - content.get("history_visibility", "shared") - }; - - history_visibility = strncpy - { - buf, _history_visibility - }; - }); - - if(history_visibility == "world_readable") - return true; - - if(empty(mxid)) - return false; - - if(m::valid(m::id::USER, mxid)) - return visible_to_user(room, history_visibility, mxid, event); - - if(rfc3986::valid_remote(std::nothrow, mxid)) - return visible_to_node(room, mxid, event); - - throw m::UNSUPPORTED - { - "Cannot determine visibility of %s for '%s'", - string_view{room.room_id}, - mxid, - }; -} - -bool -ircd::m::visible_to_user(const m::room &room, - const string_view &history_visibility, - const m::user::id &user_id, - const m::event &event) -{ - assert(history_visibility != "world_readable"); - - // Allow any member event where the state_key string is a user mxid. - if(json::get<"type"_>(event) == "m.room.member") - if(at<"state_key"_>(event) == user_id) - return true; - - // Get the membership of the user in the room at the event. - char buf[m::room::MEMBERSHIP_MAX_SIZE]; - const string_view membership - { - m::membership(buf, room, user_id) - }; - - if(membership == "join") - return true; - - if(history_visibility == "joined") - return false; - - if(membership == "invite") - return true; - - if(history_visibility == "invited") - return false; - - // The history_visibility is now likely "shared"; though we cannot assert - // that in case some other string is used for any non-spec customization - // or for graceful forward compatibility. We default to "shared" here. - //assert(history_visibility == "shared"); - - // An m::room instance with no event_id is used to query the room at the - // present state. - const m::room present - { - room.room_id - }; - - // If the room is not at the present event then we have to run another - // test for membership here. Otherwise the "join" test already failed. - if(!room.event_id) - return false; - - return m::membership(present, user_id, m::membership_positive); // join || invite -} - -bool -ircd::m::visible_to_node(const m::room &room, - const string_view &node_id, - const m::event &event) -{ - // Allow auth chain events XXX: this is too broad - if(m::room::auth::is_power_event(event)) - return true; - - // Allow any event where the state_key string is a user mxid and the server - // is the host of that user. Note that applies to any type of event. - if(m::valid(m::id::USER, json::get<"state_key"_>(event))) - if(m::user::id(at<"state_key"_>(event)).host() == node_id) - return true; - - const m::room::origins origins - { - room - }; - - // Allow joined servers - if(origins.has(node_id)) - return true; - - return false; -} diff --git a/modules/m_room_server_acl.cc b/modules/m_room_server_acl.cc index 487c271cc..fdbc225cc 100644 --- a/modules/m_room_server_acl.cc +++ b/modules/m_room_server_acl.cc @@ -74,331 +74,3 @@ ircd::m::on_changed_room_server_acl(const event &event, string_view{event.event_id}, }; } - -/////////////////////////////////////////////////////////////////////////////// -// -// ircd/m/room/server_acl.h -// - -/// Coarse control over whether ACL's are considered during the vm::eval of an -/// event, ACL's will be checked against the event's origin during processing -/// of the event, regardless of how the event was received, fetched, etc. The -/// m::vm options may dictate further detailed behavior (hard-fail, soft- -/// fail, auth integration, etc). This is the principal configuration option -/// for effecting the server access control list functionality. Though this -/// conf item is independent of other conf items in this module, setting it -/// to false denudes the core functionality. -/// -/// Setting this to true is *stricter* than the official specification and -/// fixes several vulnerabilities for bypassing ACL's. This also applies to -/// both PDU's and EDU's, and is agnostic to the method or endpoint by which -/// this server obtained the event. This departs from the specification. -/// -/// This option has no effect on the room::server_acl interface itself, it is -/// available for the callsite to check independently before using the iface. -decltype(ircd::m::room::server_acl::enable_write) -IRCD_MODULE_EXPORT_DATA -ircd::m::room::server_acl::enable_write -{ - { "name", "ircd.m.room.server_acl.enable.write" }, - { "default", true }, -}; - -/// Coarse control over whether ACL's apply to endpoints considered -/// non-modifying/passive to the room. If false, ACL's are not checked on -/// endpoints which have no visible effects to the federation; this can -/// increase performance. -/// -/// Setting this option to false relaxes the list of endpoints covered by ACL's -/// and departs from the official specification. -/// -/// This option has no effect on the room::server_acl interface itself, it is -/// available for the callsite to check independently before using the iface. -decltype(ircd::m::room::server_acl::enable_read) -IRCD_MODULE_EXPORT_DATA -ircd::m::room::server_acl::enable_read -{ - { "name", "ircd.m.room.server_acl.enable.read" }, - { "default", false }, -}; - -/// Coarse control over whether ACL's are considered for event fetching. If -/// true, events originating from an ACL'ed server will not be fetched, nor -/// will an ACL'ed server be queried by the fetch unit for any event. Note that -/// this cannot fully apply for newer event_id's without hostparts, but the -/// fetch unit may discard such events for an ACL'ed server after receiving. -/// -/// Setting this to true is *stricter* than the official specification, which -/// is vulnerable to "bouncing" around ACL's. -/// (see: https://github.com/maubot/bouncybot) -/// -/// This option has no effect on the room::server_acl interface itself, it is -/// available for the callsite to check independently before using the iface. -decltype(ircd::m::room::server_acl::enable_fetch) -IRCD_MODULE_EXPORT_DATA -ircd::m::room::server_acl::enable_fetch -{ - { "name", "ircd.m.room.server_acl.enable.fetch" }, - { "default", true }, -}; - -/// Coarse control over whether ACL's are considered when this server -/// transmits transactions to the participants in a room. If true, transactions -/// with all contained PDU's and EDU's will not be sent to ACL'ed servers. -/// -/// Setting this to true is *stricter* than the official specification, which -/// leaks all transmissions to ACL'ed servers. -/// -/// This option has no effect on the room::server_acl interface itself, it is -/// available for the callsite to check independently before using the iface. -decltype(ircd::m::room::server_acl::enable_send) -IRCD_MODULE_EXPORT_DATA -ircd::m::room::server_acl::enable_send -{ - { "name", "ircd.m.room.server_acl.enable.send" }, - { "default", true }, -}; - -bool -IRCD_MODULE_EXPORT -ircd::m::room::server_acl::check(const m::room::id &room_id, - const net::hostport &server) -try -{ - const server_acl server_acl - { - room_id - }; - - return server_acl(server); -} -catch(const std::exception &e) -{ - log::critical - { - log, "Failed to check server_acl for '%s' in %s :%s", - string(server), - string_view{room_id}, - e.what() - }; - - return false; -} - -// -// server_acl::server_acl -// - -IRCD_MODULE_EXPORT -ircd::m::room::server_acl::server_acl(const m::room &room, - const event::idx &event_idx) -:room -{ - room -} -,event_idx -{ - !event_idx? - room.get(std::nothrow, "m.room.server_acl", ""): - event_idx -} -{ -} - -bool -IRCD_MODULE_EXPORT -ircd::m::room::server_acl::operator()(const net::hostport &server) -const -{ - bool ret; - const auto closure{[this, &server, &ret] - (const json::object &content) - { - // Set the content reference here so only one actual IO is made to - // fetch the m.room.server_acl content for all queries. - const scope_restore this_content - { - this->content, content - }; - - ret = this->check(server); - }}; - - return !view(closure) || ret; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::room::server_acl::match(const string_view &prop, - const net::hostport &remote) -const -{ - // Spec sez when comparing against the server ACLs, the suspect server's - // port number must not be considered. - const string_view &server - { - net::host(remote) - }; - - return !for_each(prop, [&server] - (const string_view &expression) - { - const globular_match match - { - expression - }; - - // return false to break on match. - return match(server)? false : true; - }); -} - -bool -IRCD_MODULE_EXPORT -ircd::m::room::server_acl::has(const string_view &prop, - const string_view &expr) -const -{ - return !for_each(prop, [&expr] - (const string_view &_expr) - { - // false to break on match - return _expr == expr? false : true; - }); -} - -int -IRCD_MODULE_EXPORT -ircd::m::room::server_acl::getbool(const string_view &prop) -const -{ - int ret(-1); - view([&ret, &prop] - (const json::object &object) - { - const string_view &value - { - object[prop] - }; - - if(value == json::literal_true) - ret = 1; - else if(value == json::literal_false) - ret = 0; - }); - - return ret; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::room::server_acl::has(const string_view &prop) -const -{ - bool ret{false}; - view([&ret, &prop] - (const json::object &object) - { - ret = object.has(prop); - }); - - return ret; -} - -size_t -IRCD_MODULE_EXPORT -ircd::m::room::server_acl::count(const string_view &prop) -const -{ - size_t ret(0); - for_each(prop, [&ret] - (const string_view &) - { - ++ret; - return true; - }); - - return ret; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::room::server_acl::for_each(const string_view &prop, - const closure_bool &closure) -const -{ - bool ret{true}; - view([&ret, &closure, &prop] - (const json::object &content) - { - const json::array &list - { - content[prop] - }; - - if(!list || json::type(list, std::nothrow) != json::ARRAY) - return; - - for(auto it(begin(list)); it != end(list) && ret; ++it) - { - if(json::type(*it, json::strict, std::nothrow) != json::STRING) - continue; - - if(!closure(json::string(*it))) - ret = false; - } - }); - - return ret; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::room::server_acl::exists() -const -{ - return content || event_idx; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::room::server_acl::check(const net::hostport &server) -const -{ - // c2s 13.29.1 rules - - // 1. If there is no m.room.server_acl event in the room state, allow. - if(!exists()) - return true; - - // 2. If the server name is an IP address (v4 or v6) literal, and - // allow_ip_literals is present and false, deny. - if(getbool("allow_ip_literals") == false) - if(rfc3986::valid(std::nothrow, rfc3986::parser::ip_address, net::host(server))) - return false; - - // 3. If the server name matches an entry in the deny list, deny. - if(match("deny", server)) - return false; - - // 4. If the server name matches an entry in the allow list, allow. - if(match("allow", server)) - return true; - - // 5. Otherwise, deny. - return false; -} - -bool -IRCD_MODULE_EXPORT -ircd::m::room::server_acl::view(const view_closure &closure) -const -{ - if(content) - { - closure(content); - return true; - } - - return event_idx && m::get(std::nothrow, event_idx, "content", closure); -}