mirror of
https://github.com/matrix-construct/construct
synced 2024-05-20 03:43:47 +02:00
modules: Distill all API's from modules up to matrix lib.
This commit is contained in:
parent
d3809d43e5
commit
183e44e0b6
|
@ -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 opts> &, 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<const feds::opts>(std::addressof(opts), 1),
|
||||
closure
|
||||
}
|
||||
{}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -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}
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -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}
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -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}
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
75
matrix/breadcrumb_rooms.cc
Normal file
75
matrix/breadcrumb_rooms.cc
Normal file
|
@ -0,0 +1,75 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// 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);
|
||||
});
|
||||
}
|
|
@ -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
|
|
@ -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
|
310
matrix/device.cc
Normal file
310
matrix/device.cc
Normal file
|
@ -0,0 +1,310 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// 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<std::string, long>
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::device::count_one_time_keys(const user &user,
|
||||
const string_view &device_id)
|
||||
{
|
||||
std::map<std::string, long> 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;
|
||||
}
|
|
@ -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,
|
|
@ -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;
|
|
@ -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()
|
||||
{
|
|
@ -13,12 +13,6 @@ namespace ircd::m::events
|
|||
extern conf::item<size_t> dump_buffer_size;
|
||||
}
|
||||
|
||||
ircd::mapi::header
|
||||
IRCD_MODULE
|
||||
{
|
||||
"Matrix events library"
|
||||
};
|
||||
|
||||
decltype(ircd::m::events::dump_buffer_size)
|
||||
ircd::m::events::dump_buffer_size
|
||||
{
|
|
@ -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<const opts> &opts, const closure &closure);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -101,10 +91,10 @@ noexcept
|
|||
// m/feds.h
|
||||
//
|
||||
|
||||
bool
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::feds::execute(const vector_view<const opts> &optsv,
|
||||
const closure &closure)
|
||||
ircd::m::feds::execute::execute(const vector_view<const opts> &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<const opts> &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
|
|
@ -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
|
||||
{
|
91
matrix/ignored_user_list.cc
Normal file
91
matrix/ignored_user_list.cc
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// 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<bool> ignored_user_list_enforce_invites;
|
||||
extern conf::item<bool> 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;
|
||||
}
|
|
@ -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
|
||||
{
|
|
@ -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,
|
|
@ -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,
|
|
@ -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,
|
294
matrix/matrix.cc
294
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<const opts>{&o, 1}, c
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
ircd::m::feds::execute::execute(const vector_view<const opts> &o,
|
||||
const closure &c)
|
||||
{
|
||||
using prototype = bool (const vector_view<const opts> &, const closure &);
|
||||
|
||||
static mods::import<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> 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
|
||||
|
|
|
@ -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,
|
105
matrix/presence.cc
Normal file
105
matrix/presence.cc
Normal file
|
@ -0,0 +1,105 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// 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;
|
||||
});
|
||||
}
|
|
@ -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,
|
194
matrix/receipt.cc
Normal file
194
matrix/receipt.cc
Normal file
|
@ -0,0 +1,194 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// 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<milliseconds>()) },
|
||||
{ "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;
|
||||
}
|
140
matrix/room.cc
140
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<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> 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<prototype> call
|
||||
{
|
||||
"m_room_aliases", "ircd::m::room::aliases::cache::for_each"
|
||||
};
|
||||
|
||||
return call(s, c);
|
||||
}
|
||||
|
||||
//
|
||||
// room::power
|
||||
//
|
||||
|
|
465
matrix/room_aliases.cc
Normal file
465
matrix/room_aliases.cc
Normal file
|
@ -0,0 +1,465 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// 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<seconds> alias_fetch_timeout;
|
||||
extern conf::item<seconds> 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<mutable_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<system_point>() + (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<milliseconds>()
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
|
@ -19,12 +19,6 @@ namespace ircd::m
|
|||
extern hook::site<room::auth::hookdata &> room_auth_hook;
|
||||
}
|
||||
|
||||
ircd::mapi::header
|
||||
IRCD_MODULE
|
||||
{
|
||||
"Matrix room event authentication support."
|
||||
};
|
||||
|
||||
decltype(ircd::m::room_auth_hook)
|
||||
ircd::m::room_auth_hook
|
||||
{
|
|
@ -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
|
||||
{
|
|
@ -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
|
|
@ -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::json::array, int64_t>
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::room::head::generate(const mutable_buffer &buf,
|
150
matrix/room_history_visibility.cc
Normal file
150
matrix/room_history_visibility.cc
Normal file
|
@ -0,0 +1,150 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// 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;
|
||||
}
|
332
matrix/room_server_acl.cc
Normal file
332
matrix/room_server_acl.cc
Normal file
|
@ -0,0 +1,332 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// 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);
|
||||
}
|
|
@ -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
|
|
@ -17,12 +17,6 @@ namespace ircd::m::rooms::summary
|
|||
extern hookfn<vm::eval &> 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
|
||||
{
|
|
@ -10,12 +10,6 @@
|
|||
|
||||
using namespace ircd;
|
||||
|
||||
mapi::header
|
||||
IRCD_MODULE
|
||||
{
|
||||
"Matrix Typing"
|
||||
};
|
||||
|
||||
log::log
|
||||
typing_log
|
||||
{
|
|
@ -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)
|
|
@ -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,
|
|
@ -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()
|
|
@ -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,
|
|
@ -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,
|
|
@ -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,
|
|
@ -13,12 +13,6 @@ namespace ircd::m
|
|||
extern conf::item<seconds> remote_request_timeout;
|
||||
}
|
||||
|
||||
ircd::mapi::header
|
||||
IRCD_MODULE
|
||||
{
|
||||
"Matrix user profiles."
|
||||
};
|
||||
|
||||
decltype(ircd::m::remote_request_timeout)
|
||||
ircd::m::remote_request_timeout
|
||||
{
|
|
@ -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,
|
|
@ -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,
|
|
@ -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)
|
|
@ -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()
|
|
@ -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;
|
||||
|
|
@ -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,
|
|
@ -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 \
|
||||
###
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -20,136 +20,6 @@ IRCD_MODULE
|
|||
"Matrix device library; modular components."
|
||||
};
|
||||
|
||||
std::map<std::string, long>
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::device::count_one_time_keys(const user &user,
|
||||
const string_view &device_id)
|
||||
{
|
||||
std::map<std::string, long> 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;
|
||||
}
|
||||
|
|
|
@ -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::vm::eval &>
|
||||
_m_device_list_update_eval
|
||||
{
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// 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"
|
||||
};
|
|
@ -19,20 +19,6 @@ IRCD_MODULE
|
|||
"14.24 :Ignoring Users"
|
||||
};
|
||||
|
||||
conf::item<bool>
|
||||
enforce_invites
|
||||
{
|
||||
{ "name", "ircd.m.ignored_user_list.enforce.invites" },
|
||||
{ "default", true }
|
||||
};
|
||||
|
||||
conf::item<bool>
|
||||
enforce_events
|
||||
{
|
||||
{ "name", "ircd.m.ignored_user_list.enforce.events" },
|
||||
{ "default", false }
|
||||
};
|
||||
|
||||
/*
|
||||
m::hookfn<m::vm::eval &>
|
||||
_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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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<milliseconds>()) },
|
||||
{ "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(),
|
||||
};
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
|
||||
namespace ircd::m
|
||||
{
|
||||
extern conf::item<seconds> alias_fetch_timeout;
|
||||
extern conf::item<seconds> 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<mutable_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<system_point>() + (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<milliseconds>()
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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<vm::eval &> 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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue