0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-05-20 03:43:47 +02:00

matrix: Add m::homeserver; preliminary virtual origin networks.

This commit is contained in:
Jason Volk 2019-09-30 20:50:58 -07:00
parent b17b8b0bef
commit dbb3c55db5
51 changed files with 1350 additions and 856 deletions

View file

@ -68,7 +68,6 @@ construct_LDADD = \
construct_SOURCES = \
construct.cc \
matrix.cc \
signals.cc \
console.cc \
lgetopt.cc \

View file

@ -13,7 +13,6 @@
#include <ircd/asio.h>
#include "lgetopt.h"
#include "construct.h"
#include "matrix.h"
#include "signals.h"
#include "console.h"
@ -120,8 +119,13 @@ noexcept try
if(printversion)
return print_version();
// The matrix origin is the first positional argument after any switched
// arguments. The matrix origin is the hostpart of MXID's for the server.
// Sets various other conf items based on the program options captured into
// the globals preceding this frame.
applyargs();
// The network name (matrix origin) is the first positional argument after
// any switched arguments. The matrix origin is the hostpart of MXID's for
// the server.
const ircd::string_view origin
{
argc > 0?
@ -129,46 +133,42 @@ noexcept try
nullptr
};
// The hostname is the unique name for this specific server. This is
// The server_name is the unique name for this specific server. This is
// generally the same as origin; but if origin is example.org with an
// SRV record redirecting to matrix.example.org then hostname is
// SRV record redirecting to matrix.example.org then server_name is
// matrix.example.org. In clusters serving a single origin, all
// hostnames must be different.
const ircd::string_view hostname
// server_names must be different.
const ircd::string_view server_name
{
argc > 1? // hostname given on command line
argc > 1? // server_name given on command line
argv[1]:
argc > 0? // hostname matches origin
argc > 0? // server_name matches origin
argv[0]:
nullptr
};
// at least one hostname argument is required for now.
if(!hostname)
// at least one server_name argument is required for now.
if(!server_name)
throw ircd::user_error
{
"usage :%s <origin> [servername]", progname
};
// Set the required name conf items based on the positional program
// arguments. This operation will throw if the strings are not fit for
// purpose as host/domain names.
ircd::network_name.set(origin);
ircd::server_name.set(hostname);
// Sets various other conf items based on the program options captured into
// the globals preceding this frame.
applyargs();
// The smoketest uses this ircd::run::level callback to set a flag when
// each ircd::run::level is reached. All flags must be set to pass. The
// smoketest is inert unless the -smoketest program option is used.
const ircd::run::changed smoketester{[](const auto &level)
// smoketest is inert unless the -smoketest program option is used. Note
// the special case for run::level::RUN, which initiates the transition
// to QUIT; the ircd::post allows any operations queued in the io_context
// to run in case the smoketest isn't the only callback being invoked.
const ircd::run::changed smoketester
{
smoketest.at(size_t(level) + 1) = true;
if(smoketest[0] && level == ircd::run::level::RUN)
ircd::post {[] { ircd::quit(); }};
}};
[](const auto &level)
{
smoketest.at(size_t(level) + 1) = true;
if(smoketest[0] && level == ircd::run::level::RUN)
ircd::post {[] { ircd::quit(); }};
}
};
// This is the sole io_context for Construct, and the ios.run() below is the
// the only place where the program actually blocks.
@ -187,9 +187,88 @@ noexcept try
// to that io_context. Execution of IRCd will then occur during ios::run()
ircd::init(ios);
// Start matrix application.
if(likely(!nomatrix))
construct::matrix::init();
// Setup synchronization primitives on this stack for starting and stopping
// the application (matrix homeserver). Note this stack cannot actually use
// these; they'll be used to synchronize the closures below running in
// different contexts.
ircd::ctx::latch start(2), quit(2);
// Setup the matrix homeserver application. This will be executed on an
// ircd::context (dedicated stack). We construct several objects on the
// stack which are the basis for our matrix homeserver. When the stack
// unwinds, the homeserver will go out of service.
const auto homeserver{[&origin, &server_name, &start, &quit]
{
// 5
struct ircd::m::homeserver::opts opts;
opts.origin = origin;
opts.server_name = server_name;
// 6
// Load the matrix library dynamic shared object
ircd::matrix matrix;
// 7
// Run a primary homeserver based on the program options given.
const ircd::custom_ptr<ircd::m::homeserver> homeserver
{
// 7.1
matrix.init(&opts), [&matrix]
(ircd::m::homeserver *const homeserver)
{
// 13.1
matrix.fini(homeserver);
}
};
// 8
// Notify the loader the homeserver is ready for service.
start.count_down_and_wait();
// 9
// Yield until the loader notifies us; this stack will then unwind.
quit.count_down_and_wait();
// 13
}};
// This object registers a callback for a specific event in libircd; the
// closure is called from the main context (#1) running ircd::main().
// after libircd is ready for service in runlevel START but before entering
// runlevel RUN. It is called again immediately after entering runlevel
// QUIT, but before any functionality of libircd destructs. This cues us
// to start and stop the homeserver.
const decltype(ircd::run::main)::callback loader
{
ircd::run::main, [&homeserver, &start, &quit]
{
static ircd::context context;
// 2 This branch is taken the first time this function is called,
// and not taken the second time.
if(!context)
{
// 3 Launch the homeserver context (asynchronous).
context = { "matrix", homeserver };
// 4 Yield until the homeserver function notifies `start`; waiting
// here prevents ircd::main() from entering runlevel RUN.
start.count_down_and_wait();
// 10
return;
}
// 11
// Notify the waiting homeserver context to quit; this will
// start shutting down the homeserver.
quit.count_down_and_wait();
// 12
// Wait for the homeserver context to finish before we return.
context.join();
}
};
// If the user wants to immediately drop to an interactive command line
// without having to send a ctrl-c for it, that is provided here. This does
@ -207,10 +286,12 @@ noexcept try
if(norun)
return EXIT_SUCCESS;
// 1
// Execution.
// Blocks until a clean exit from a quit() or an exception comes out of it.
ios.run();
// 14
// The smoketest is enabled if the first value is true; then all of the
// values must be true for the smoketest to pass.
if(smoketest[0])
@ -331,6 +412,8 @@ enable_coredumps()
}
#endif
/// These operations are safe to call before ircd::init() and anytime after
/// static initialization.
void
applyargs()
{

View file

@ -1,116 +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.
#include <ircd/matrix.h>
#include "construct.h"
#include "matrix.h"
decltype(construct::matrix)
construct::matrix;
void
construct::matrix::init()
{
assert(construct::matrix == nullptr);
construct::matrix = new matrix{};
}
void
construct::matrix::quit()
{
if(!construct::matrix)
return;
construct::matrix->context.terminate();
}
construct::matrix::matrix()
:context
{
"matrix",
1048576,
std::bind(&matrix::main, this),
ircd::context::DISPATCH,
}
{
}
construct::matrix::~matrix()
noexcept
{
}
void
construct::matrix::main()
noexcept try
{
ircd::run::changed::dock.wait([]
{
return ircd::run::level != ircd::run::level::READY;
});
if(ircd::run::level != ircd::run::level::START || ircd::run::level != ircd::run::level::RUN)
return;
ircd::matrix instance
{
};
const ircd::scope_restore this_instance
{
this->instance, std::addressof(instance)
};
ircd::mods::import<ircd::log::log> log
{
instance.module, "ircd::m::log"
};
ircd::log::notice
{
log, "Matrix Constructed"
};
dock.notify_all();
ircd::run::changed::dock.wait([]
{
return false
|| ircd::run::level == ircd::run::level::QUIT
|| ircd::run::level == ircd::run::level::HALT
;
});
ircd::log::notice
{
log, "Matrix Shutdown..."
};
}
catch(const ircd::ctx::interrupted &e)
{
ircd::log::debug
{
"construct::matrix :%s", e.what()
};
}
catch(const ircd::ctx::terminated &e)
{
ircd::log::debug
{
"construct::matrix: terminated."
};
}
catch(const std::exception &e)
{
ircd::log::error
{
"construct::matrix :%s", e.what()
};
}

View file

@ -1,34 +0,0 @@
// 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
{
struct matrix;
}
namespace construct
{
struct matrix;
}
struct construct::matrix
{
ircd::ctx::dock dock;
ircd::context context;
ircd::matrix *instance {nullptr};
void main() noexcept;
matrix();
~matrix() noexcept;
static void init();
static void quit();
};

View file

@ -13,7 +13,6 @@
#include "construct.h"
#include "signals.h"
#include "console.h"
#include "matrix.h"
namespace construct
{

View file

@ -82,9 +82,6 @@ namespace ircd
extern conf::item<bool> write_avoid;
extern conf::item<bool> soft_assert;
extern conf::item<std::string> server_name;
extern conf::item<std::string> network_name;
seconds uptime();
void init(boost::asio::io_context &ios);
void cont() noexcept;

View file

@ -11,6 +11,12 @@
#pragma once
#define HAVE_IRCD_M_EVENT_APPEND
//XXX fwd decl
namespace ircd::m
{
struct room;
};
/// Used when transmitting events to clients. This tries to hide and provide
/// as much boilerplate as possible which we abstracted from all of the
/// different locations where an event may be revealed to a client. This device

115
include/ircd/m/homeserver.h Normal file
View file

@ -0,0 +1,115 @@
// 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.
#pragma once
#define HAVE_IRCD_M_HOMESERVER_H
namespace ircd::m
{
struct homeserver;
IRCD_M_EXCEPTION(error, NOT_MY_HOMESERVER, http::NOT_FOUND)
IRCD_M_EXCEPTION(error, NOT_A_HOMESERVER, http::SERVICE_UNAVAILABLE)
string_view origin(const homeserver &);
string_view server_name(const homeserver &);
bool origin(const homeserver &, const string_view &);
bool server_name(const homeserver &, const string_view &);
string_view public_key_id(const homeserver &);
const ed25519::sk &secret_key(const homeserver &);
bool for_each(const std::function<bool (homeserver &)> &);
homeserver &my(const string_view &origin);
homeserver &my(); // primary
user::id me(const string_view &origin);
user::id me(); // primary
}
///NOTE: instance_multimap is used because there is no instance_map yet.
struct ircd::m::homeserver
:instance_multimap<string_view, homeserver, std::less<>>
{
struct key;
struct cert;
struct opts;
/// Internal state; use m::my().
static homeserver *primary;
/// Options from the user.
const struct opts *opts;
/// Federation key related.
std::unique_ptr<struct key> key;
/// Database
std::shared_ptr<dbs::init> database;
/// List of special room specific to this homeserver. This includes the
/// fundamental !ircd room, !conf room, etc. This list generally doesn't
/// change after construction, but it's mutable to allow modules to add
/// new rooms to the list.
std::set<m::room::id::buf> rooms;
/// An inscription of @ircd:network.name to root various references to
/// a user representing the server.
m::user::id::buf self;
/// Loaded modules.
std::list<ircd::module> modules;
homeserver(const struct opts *const &);
~homeserver() noexcept;
/// Factory to create homeserver with single procedure for shlib purposes.
static homeserver *init(const struct opts *);
static void fini(homeserver *) noexcept;
};
struct ircd::m::homeserver::key
{
/// Current federation secret key instance
ed25519::sk secret_key;
/// Current federation public key instance
ed25519::pk public_key;
/// Current federation public key base64
std::string public_key_b64;
/// Current ed25519:ident string
std::string public_key_id;
key(const string_view &origin);
key() = default;
};
struct ircd::m::homeserver::cert
{
std::string tls_private_key_path;
std::string tls_public_key_path;
std::string tls_cert_path;
};
struct ircd::m::homeserver::opts
{
/// Network name. This is the mxid hostpart (i.e @user:origin).
string_view origin;
/// This server's name. This is the unique domain-name of this server
/// participating in the cluster to serve the origin. The servername may
/// be the origin itself; otherwise, SRV/well-known indirection is required
/// to reach the servername starting from the origin.
string_view server_name;
};

View file

@ -35,6 +35,7 @@ namespace ircd::m
namespace ircd::m
{
struct matrix;
struct homeserver;
IRCD_OVERLOAD(generate)
@ -48,9 +49,8 @@ namespace ircd
#include "name.h"
#include "error.h"
#include "self.h"
#include "init.h"
#include "id.h"
#include "self.h"
#include "event/event.h"
#include "get.h"
#include "query.h"
@ -89,9 +89,13 @@ namespace ircd
#include "media.h"
#include "search.h"
#include "resource.h"
#include "homeserver.h"
struct ircd::m::matrix
{
static const std::vector<string_view> module_names;
static const std::vector<string_view> module_names_optional;
std::string module_path
{
fs::path_string(fs::base::LIB, "libircd_matrix")
@ -101,4 +105,16 @@ struct ircd::m::matrix
{
module_path
};
using init_proto = m::homeserver *(const struct m::homeserver::opts *);
mods::import<init_proto> init
{
module, "ircd::m::homeserver::init"
};
using fini_proto = void (m::homeserver *) noexcept;
mods::import<fini_proto> fini
{
module, "ircd::m::homeserver::fini"
};
};

View file

@ -13,56 +13,27 @@
namespace ircd::m::self
{
struct init;
// Test if provided string is one of my homeserver's network_name()'s.
bool my_host(const string_view &);
extern std::string origin;
extern std::string servername;
extern ed25519::sk secret_key;
extern ed25519::pk public_key;
extern std::string public_key_b64;
extern std::string public_key_id;
extern std::string tls_cert_der;
extern std::string tls_cert_der_sha256_b64;
string_view host();
// Similar to my_host(), but the comparison is relaxed to allow port
// numbers to be a factor: myself.com:8448 input will match if a homeserver
// here has a network_name of myself.com. OTOH, myself.com:1234 (i.e some
// non-canonical port) can only match a homeserver here with the explicit
// name of myself.com:1234.
bool host(const string_view &);
void create_my_key();
void signon(), signoff();
// Alias for origin(my()); primary homeserver's network name
string_view my_host(); //__attribute__((deprecated));
}
namespace ircd::m
{
extern struct user me;
extern struct room my_room;
extern struct node my_node;
string_view my_host();
bool my_host(const string_view &);
using self::my_host;
using self::host;
}
namespace ircd
{
using m::my_host;
}
struct ircd::m::self::init
{
static void federation_ed25519();
static void tls_certificate();
static void keys();
init();
};
inline ircd::string_view
ircd::m::my_host()
{
return self::host();
}
inline bool
ircd::m::my_host(const string_view &host)
{
return self::host(host);
}

View file

@ -48,8 +48,6 @@ struct ircd::m::user
using closure = std::function<void (const user &)>;
using closure_bool = std::function<bool (const user &)>;
static m::room tokens;
id user_id;
operator const id &() const;

View file

@ -88,42 +88,6 @@ ircd::restart
{ "persist", false },
};
decltype(ircd::server_name)
ircd::server_name
{
{
{ "name", "ircd.name.server" },
{ "default", "localhost" },
{ "persist", false },
}, []
{
if(!rfc3986::valid_remote(std::nothrow, ircd::server_name))
throw user_error
{
"The 'ircd.name.server' conf \"%s\" is not a valid hostname.",
string_view(server_name),
};
}
};
decltype(ircd::network_name)
ircd::network_name
{
{
{ "name", "ircd.name.network" },
{ "default", "localhost" },
{ "persist", false },
}, []
{
if(!rfc3986::valid_remote(std::nothrow, ircd::network_name))
throw user_error
{
"The 'ircd.name.network' conf \"%s\" is not a valid hostname.",
string_view(network_name),
};
}
};
decltype(ircd::main_context)
ircd::main_context;

View file

@ -57,7 +57,6 @@ 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 += self.cc
libircd_matrix_la_SOURCES += hook.cc
libircd_matrix_la_SOURCES += event.cc
libircd_matrix_la_SOURCES += event_cached.cc
@ -127,7 +126,7 @@ libircd_matrix_la_SOURCES += filter.cc
libircd_matrix_la_SOURCES += txn.cc
libircd_matrix_la_SOURCES += vm.cc
libircd_matrix_la_SOURCES += init_backfill.cc
libircd_matrix_la_SOURCES += init_bootstrap.cc
libircd_matrix_la_SOURCES += homeserver.cc
libircd_matrix_la_SOURCES += resource.cc
libircd_matrix_la_SOURCES += matrix.cc

View file

@ -259,7 +259,7 @@ try
item.get(vbuf)
};
return set_conf_item(m::me.user_id, key, val);
return set_conf_item(m::me(), key, val);
}
catch(const std::exception &e)
{
@ -278,7 +278,7 @@ create_conf_room(const m::event &,
m::vm::eval &)
{
const m::conf_room conf_room;
m::create(conf_room.room_id, m::me.user_id);
m::create(conf_room.room_id, m::me());
//rehash_conf({}, true);
}

View file

@ -302,7 +302,16 @@ 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::room::id::buf tokens
{
"tokens", origin(my())
};
const m::room::state &state
{
tokens
};
const m::event::idx &event_idx
{
state.get(std::nothrow, "ircd.access_token", token)

View file

@ -182,20 +182,30 @@ ircd::m::event::signatures(const mutable_buffer &out,
json::iov &event,
const json::iov &content)
{
const string_view &origin
{
event.at("origin")
};
const ed25519::sig sig
{
sign(event, content)
};
const string_view public_key_id
{
m::public_key_id(my(origin))
};
thread_local char sigb64buf[b64encode_size(sizeof(sig))];
const json::members sigb64
{
{ self::public_key_id, b64encode_unpadded(sigb64buf, sig) }
{ public_key_id, b64encode_unpadded(sigb64buf, sig) }
};
const json::members sigs
{
{ event.at("origin"), sigb64 }
{ origin, sigb64 }
};
return json::stringify(mutable_buffer{out}, sigs);
@ -222,19 +232,22 @@ ircd::m::signatures(const mutable_buffer &out_,
sign(preimage)
};
const auto sig_host
const auto &origin
{
my_host(json::get<"origin"_>(event))?
json::get<"origin"_>(event):
my_host()
json::at<"origin"_>(event)
};
const string_view public_key_id
{
m::public_key_id(my(origin))
};
thread_local char sigb64buf[b64encode_size(sizeof(sig))];
const json::member my_sig
{
sig_host, json::members
origin, json::members
{
{ self::public_key_id, b64encode_unpadded(sigb64buf, sig) }
{ public_key_id, b64encode_unpadded(sigb64buf, sig) }
}
};
@ -257,7 +270,17 @@ ircd::ed25519::sig
ircd::m::event::sign(json::iov &event,
const json::iov &contents)
{
return sign(event, contents, self::secret_key);
const string_view &origin
{
event.at("origin")
};
const auto &secret_key
{
m::secret_key(my(origin))
};
return sign(event, contents, secret_key);
}
ircd::ed25519::sig
@ -278,7 +301,17 @@ ircd::m::event::sign(json::iov &event,
ircd::ed25519::sig
ircd::m::sign(const event &event)
{
return sign(event, self::secret_key);
const string_view &origin
{
json::at<"origin"_>(event)
};
const auto &secret_key
{
m::secret_key(my(origin))
};
return sign(event, secret_key);
}
ircd::ed25519::sig
@ -297,7 +330,17 @@ ircd::m::sign(const event &event,
ircd::ed25519::sig
ircd::m::event::sign(const json::object &event)
{
return sign(event, self::secret_key);
const json::string &origin
{
event.at("origin")
};
const auto &secret_key
{
m::secret_key(my(origin))
};
return sign(event, secret_key);
}
ircd::ed25519::sig
@ -317,7 +360,17 @@ ircd::m::event::sign(const json::object &event,
ircd::ed25519::sig
ircd::m::event::sign(const string_view &event)
{
return sign(event, self::secret_key);
const json::string &origin
{
json::object(event).at("origin")
};
const auto &secret_key
{
m::secret_key(my(origin))
};
return sign(event, secret_key);
}
ircd::ed25519::sig
@ -766,7 +819,7 @@ ircd::m::make_id(const event &event,
{
const id::event ret
{
buf, b64tob64url(readable, b64encode_unpadded(readable, hash)), my_host()
buf, b64tob64url(readable, b64encode_unpadded(readable, hash)), at<"origin"_>(event)
};
buf.assigned(ret);

View file

@ -87,7 +87,6 @@ ircd::m::vm::conform_check_size
{
{
{ "_site", "vm.conform" },
{ "origin", my_host() }
},
[](const m::event &event, eval &eval)
{

559
matrix/homeserver.cc Normal file
View file

@ -0,0 +1,559 @@
// 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 void bootstrap(homeserver &);
}
// Linkage for the container of all active clients for iteration purposes.
template<>
decltype(ircd::util::instance_multimap<ircd::string_view, ircd::m::homeserver, std::less<>>::map)
ircd::util::instance_multimap<ircd::string_view, ircd::m::homeserver, std::less<>>::map
{};
[[gnu::hot]]
ircd::m::user::id
ircd::m::me()
{
auto &my
{
m::my()
};
return my.self;
}
[[gnu::hot]]
ircd::m::user::id
ircd::m::me(const string_view &origin)
{
auto &my
{
m::my(origin)
};
return my.self;
}
[[gnu::hot]]
ircd::m::homeserver &
ircd::m::my()
{
if(unlikely(!homeserver::primary))
throw m::NOT_A_HOMESERVER
{
"I do not host any homeserver here."
};
return *homeserver::primary;
}
[[gnu::hot]]
ircd::m::homeserver &
ircd::m::my(const string_view &name)
{
const auto &it
{
homeserver::map.find(name)
};
if(unlikely(it == end(homeserver::map)))
throw m::NOT_MY_HOMESERVER
{
"I do not host any '%s' homeserver here.",
name,
};
const auto &ptr
{
it->second
};
assert(ptr);
return *ptr;
}
bool
ircd::m::for_each(const std::function<bool (homeserver &)> &closure)
{
for(auto &[name, hs_p] : homeserver::map)
if(!closure(*hs_p))
return false;
return true;
}
const ircd::ed25519::sk &
ircd::m::secret_key(const homeserver &homeserver)
{
assert(homeserver.key);
return homeserver.key->secret_key;
}
ircd::string_view
ircd::m::public_key_id(const homeserver &homeserver)
{
assert(homeserver.key);
return homeserver.key->public_key_id;
}
bool
ircd::m::server_name(const homeserver &homeserver,
const string_view &server_name)
{
return server_name == m::server_name(homeserver);
}
bool
ircd::m::origin(const homeserver &homeserver,
const string_view &origin)
{
return origin == m::origin(homeserver);
}
ircd::string_view
ircd::m::server_name(const homeserver &homeserver)
{
assert(homeserver.opts);
return homeserver.opts->server_name;
}
ircd::string_view
ircd::m::origin(const homeserver &homeserver)
{
assert(homeserver.opts);
return homeserver.opts->origin;
}
//
// homeserver::homeserver
//
decltype(ircd::m::homeserver::primary)
ircd::m::homeserver::primary;
ircd::m::homeserver *
IRCD_MODULE_EXPORT
ircd::m::homeserver::init(const struct opts *const opts)
{
return new homeserver
{
opts
};
}
void
IRCD_MODULE_EXPORT
ircd::m::homeserver::fini(homeserver *const homeserver)
noexcept
{
delete homeserver;
}
//
// homeserver::homeserver::homeserver
//
IRCD_MODULE_EXPORT
ircd::m::homeserver::homeserver(const struct opts *const &opts)
:instance_multimap
{
string_view{opts->origin}
}
,opts
{
opts
}
,key
{
std::make_unique<struct key>(opts->origin)
}
,database
{
std::make_shared<dbs::init>(opts->server_name, std::string{})
}
,rooms
{
{ "ircd", opts->origin },
}
,self
{
"ircd", opts->origin
}
{
primary = primary?: this;
modules =
{
begin(matrix::module_names), end(matrix::module_names)
};
if(primary == this && dbs::events && sequence(*dbs::events) == 0)
bootstrap(*this);
}
ircd::m::homeserver::~homeserver()
noexcept
{
while(!modules.empty())
modules.pop_back();
}
//
// homeserver::keys
//
/*
namespace ircd::m
{
extern conf::item<std::string> ed25519_key_dir;
}
decltype(ircd::m::ed25519_key_dir)
ircd::m::ed25519_key_dir
{
{ "name", "ircd.keys.ed25519_key_dir" },
{ "default", fs::cwd() },
};
void
IRCD_MODULE_EXPORT
ircd::m::self::init::federation_ed25519()
{
if(empty(m::self::origin))
throw error
{
"The m::self::origin must be set to init my ed25519 key."
};
const std::string path_parts[]
{
std::string{ed25519_key_dir},
m::self::origin + ".ed25519",
};
const std::string sk_file
{
ircd::string(fs::PATH_MAX_LEN, [&](const mutable_buffer &buf)
{
return fs::path(buf, path_parts);
})
};
if(fs::exists(sk_file) || ircd::write_avoid)
log::info
{
m::log, "Using ed25519 secret key @ `%s'", sk_file
};
else
log::notice
{
m::log, "Creating ed25519 secret key @ `%s'", sk_file
};
m::self::secret_key = ed25519::sk
{
sk_file, &m::self::public_key
};
m::self::public_key_b64 = b64encode_unpadded(m::self::public_key);
const fixed_buffer<const_buffer, sha256::digest_size> hash
{
sha256{m::self::public_key}
};
const auto public_key_hash_b58
{
b58encode(hash)
};
static const auto trunc_size{8};
m::self::public_key_id = fmt::snstringf
{
32, "ed25519:%s", trunc(public_key_hash_b58, trunc_size)
};
log::info
{
m::log, "Current key is '%s' and the public key is: %s",
m::self::public_key_id,
m::self::public_key_b64
};
}
*/
//
// create_my_key
//
ircd::m::homeserver::key::key(const string_view &origin)
{
/*
const json::members verify_keys_
{{
string_view{m::self::public_key_id},
{
{ "key", m::self::public_key_b64 }
}
}};
m::keys my_key;
json::get<"server_name"_>(my_key) = my_host();
json::get<"old_verify_keys"_>(my_key) = "{}";
//TODO: conf
json::get<"valid_until_ts"_>(my_key) =
ircd::time<milliseconds>() + milliseconds(1000UL * 60 * 60 * 24 * 180).count();
const json::strung verify_keys{verify_keys_}; // must be on stack until my_keys serialized.
json::get<"verify_keys"_>(my_key) = verify_keys;
const json::strung presig
{
my_key
};
const ed25519::sig sig
{
m::self::secret_key.sign(const_buffer{presig})
};
char signature[256];
const json::strung signatures{json::members
{
{ my_host(),
{
{ string_view{m::self::public_key_id}, b64encode_unpadded(signature, sig) }
}}
}};
json::get<"signatures"_>(my_key) = signatures;
keys::cache::set(json::strung{my_key});
*/
}
///////////////////////////////////////////////////////////////////////////////
//
// m/self.h
//
ircd::string_view
ircd::m::self::my_host()
{
return origin(my());
}
bool
ircd::m::self::host(const string_view &other)
{
const net::hostport other_host{other};
for(const auto &[my_network, hs_p] : homeserver::map)
{
// port() is 0 when the origin has no port (and implies 8448)
const auto port
{
net::port(net::hostport(my_network))
};
// If my_host has a port number, then the argument must also have the
// same port number.
if(port && my_network == other)
return true;
else if(port)
continue;
/// If my_host has no port number, then the argument can have port
/// 8448 or no port number, which will initialize net::hostport.port to
/// the "canon_port" of 8448.
assert(net::canon_port == 8448);
if(net::port(other_host) != net::canon_port)
continue;
/// Both myself and input are using 8448; now the name has to match.
if(my_network != host(other_host))
continue;
return true;
}
return false;
}
bool
ircd::m::self::my_host(const string_view &name)
{
const auto it
{
homeserver::map.find(name)
};
return it != end(homeserver::map);
}
//
// signon/signoff greetings
//
/*
namespace ircd::m::self
{
void signon(), signoff();
}
ircd::conf::item<std::string>
me_online_status_msg
{
{ "name", "ircd.me.online.status_msg" },
{ "default", "Wanna chat? IRCd at your service!" }
};
ircd::conf::item<std::string>
me_offline_status_msg
{
{ "name", "ircd.me.offline.status_msg" },
{ "default", "Catch ya on the flip side..." }
};
void
ircd::m::self::signon()
{
if(!ircd::write_avoid && vm::sequence::retired != 0)
presence::set(me, "online", me_online_status_msg);
}
void
ircd::m::self::signoff()
{
if(!std::uncaught_exceptions() && !ircd::write_avoid)
presence::set(me, "offline", me_offline_status_msg);
}
//
// init
//
ircd::m::self::init::init()
try
{
// Sanity check that these are valid hostname strings. This was likely
// already checked, so these validators will simply throw without very
// useful error messages if invalid strings ever make it this far.
rfc3986::valid_host(origin);
rfc3986::valid_host(servername);
ircd_user_id = {"ircd", origin};
m::me = {ircd_user_id};
ircd_room_id = {"ircd", origin};
m::my_room = {ircd_room_id};
if(origin == "localhost")
log::warning
{
"The origin is configured or has defaulted to 'localhost'"
};
}
catch(const std::exception &e)
{
log::critical
{
m::log, "Failed to init self origin[%s] servername[%s]",
origin,
servername,
};
throw;
}
static const auto self_init{[]
{
ircd::m::self::init();
return true;
}()};
*/
void
ircd::m::bootstrap(homeserver &homeserver)
try
{
assert(dbs::events);
assert(db::sequence(*dbs::events) == 0);
if(homeserver.self.hostname() == "localhost")
log::warning
{
"The server's name is configured to localhost. This is probably not what you want."
};
if(!exists(homeserver.self))
{
create(homeserver.self);
user(homeserver.self).activate();
}
const m::room::id::buf node_room_id
{
node(origin(homeserver)).room_id()
};
if(!exists(node_room_id))
create(room(node_room_id));
const m::room::id::buf my_room
{
"ircd", origin(homeserver)
};
if(!exists(my_room))
create(my_room, homeserver.self, "internal");
if(!membership(my_room, homeserver.self, "join"))
join(room(my_room), user(homeserver.self));
if(!room(my_room).has("m.room.name", ""))
send(my_room, homeserver.self, "m.room.name", "",
{
{ "name", "IRCd's Room" }
});
if(!room(my_room).has("m.room.topic", ""))
send(my_room, homeserver.self, "m.room.topic", "",
{
{ "topic", "The daemon's den." }
});
const m::room::id::buf tokens_room
{
"tokens", origin(homeserver)
};
if(!exists(tokens_room))
create(tokens_room, homeserver.self);
if(!room(tokens_room).has("m.room.name",""))
send(tokens_room, homeserver.self, "m.room.name", "",
{
{ "name", "User Tokens" }
});
log::info
{
log, "Bootstrap event generation completed nominally."
};
}
catch(const std::exception &e)
{
throw ircd::panic
{
"bootstrap %s error :%s",
server_name(homeserver),
e.what()
};
}

View file

@ -207,7 +207,7 @@ const
ircd::m::hook::base::base(const json::members &members)
:_feature
{
_hook_make_feature(members)
members // _hook_make_feature(members)
}
,feature
{

View file

@ -8,6 +8,11 @@
// 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::init
{
struct backfill;
}
/// This should be a namespace but we're stuck in struct m::init for now, so
/// this code should be portable for a future when m::init is unstructured.
struct ircd::m::init::backfill

View file

@ -1,71 +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.
ircd::m::init::bootstrap::bootstrap()
try
{
assert(dbs::events);
assert(db::sequence(*dbs::events) == 0);
if(me.user_id.hostname() == "localhost")
log::warning
{
"The ircd.origin is configured to localhost. This is probably not"
" what you want. To fix this now, you will have to remove the "
" database and start over."
};
if(!exists(me))
{
create(me.user_id);
me.activate();
}
if(!exists(my_node))
create(my_node);
if(!exists(my_room))
create(my_room, me.user_id, "internal");
if(!membership(my_room, me, "join"))
join(my_room, me.user_id);
if(!my_room.has("m.room.name", ""))
send(my_room, me.user_id, "m.room.name", "",
{
{ "name", "IRCd's Room" }
});
if(!my_room.has("m.room.topic", ""))
send(my_room, me.user_id, "m.room.topic", "",
{
{ "topic", "The daemon's den." }
});
if(!exists(user::tokens))
create(user::tokens, me.user_id);
if(!user::tokens.has("m.room.name",""))
send(user::tokens, me.user_id, "m.room.name", "",
{
{ "name", "User Tokens" }
});
log::info
{
log, "Bootstrap event generation completed nominally."
};
}
catch(const std::exception &e)
{
throw ircd::panic
{
"bootstrap error :%s", e.what()
};
}

View file

@ -476,7 +476,7 @@ ircd::m::keys::cache::set(const json::object &keys)
};
if(!exists(node_room.room_id))
create(node_room, m::me.user_id);
create(node_room, me());
const json::object &vks
{
@ -490,7 +490,7 @@ ircd::m::keys::cache::set(const json::object &keys)
return ret;
const auto &key_id(unquote(member.first));
send(node_room, m::me.user_id, "ircd.key", key_id, keys);
send(node_room, me(), "ircd.key", key_id, keys);
++ret;
}

View file

@ -28,169 +28,12 @@ ircd::m::log
"m", 'm'
};
//
// init
//
/// --- tmp ---
extern "C" void
reload_conf();
namespace ircd::m
{
std::unique_ptr<dbs::init> _dbs;
std::unique_ptr<fetch::init> _fetch;
std::unique_ptr<init::modules> _modules;
}
/// --- /tmp ---
void
ircd::m::on_load()
try
{
assert(ircd::run::level == run::level::START);
m::self::init::keys();
_dbs = std::make_unique<dbs::init>(ircd::server_name, std::string{});
reload_conf();
_fetch = std::make_unique<fetch::init>();
_modules = std::make_unique<init::modules>();
self::signon();
}
catch(const m::error &e)
{
log::error
{
log, "Failed to start matrix (%u) %s :%s :%s",
uint(e.code),
http::status(e.code),
e.errcode(),
e.errstr(),
};
throw;
}
catch(const std::exception &e)
{
log::error
{
log, "Failed to start matrix :%s", e.what()
};
throw;
}
void
ircd::m::on_unload()
noexcept try
{
mods::imports.erase("m_listen"s);
if(m::sync::pool.size())
m::sync::pool.join();
self::signoff();
_fetch.reset(nullptr);
_modules.reset(nullptr);
_dbs.reset(nullptr);
//TODO: remove this for non-interfering shutdown
server::interrupt_all();
client::terminate_all();
client::close_all();
server::close_all();
server::wait_all();
client::wait_all();
}
catch(const m::error &e)
{
log::critical
{
log, "%s %s", e.what(), e.content
};
ircd::terminate();
}
//
// init::modules
//
namespace ircd::m
{
extern const std::vector<string_view> module_names;
extern const std::vector<string_view> module_names_optional;
}
ircd::m::init::modules::modules()
{
const unwind::exceptional unload{[this]
{
this->fini_imports();
}};
init_imports();
}
ircd::m::init::modules::~modules()
noexcept
{
fini_imports();
}
void
ircd::m::init::modules::init_imports()
{
if(!bool(ircd::mods::autoload))
{
log::warning
{
"Not loading modules because noautomod flag is set. "
"You may still load modules manually."
};
return;
}
for(const auto &name : module_names) try
{
mods::imports.emplace(name, name);
}
catch(...)
{
const auto &optional(module_names_optional);
if(std::count(begin(optional), end(optional), name))
continue;
throw;
}
if(vm::sequence::retired == 0)
{
log::notice
{
log, "This appears to be your first time running IRCd because the events "
"database is empty. I will be bootstrapping it with initial events now..."
};
m::init::bootstrap{};
}
}
void
ircd::m::init::modules::fini_imports()
noexcept
{
for(auto it(module_names.rbegin()); it != module_names.rend(); ++it)
mods::imports.erase(*it);
}
/// This is an ordered list for loading and unloading modules. This is not the
/// solution I really want at all so consider it temporary. Modules are loaded
/// in the order of the lines and unloaded in reverse order.
decltype(ircd::m::module_names)
ircd::m::module_names
IRCD_MODULE_EXPORT_DATA
decltype(ircd::m::matrix::module_names)
ircd::m::matrix::module_names
{
"m_noop",
"m_breadcrumb_rooms",
@ -313,8 +156,165 @@ ircd::m::module_names
/// This is a list of modules that are considered "optional" and any loading
/// error for them will not propagate and interrupt m::init.
decltype(ircd::m::module_names_optional)
ircd::m::module_names_optional
IRCD_MODULE_EXPORT_DATA
decltype(ircd::m::matrix::module_names_optional)
ircd::m::matrix::module_names_optional
{
"web_hook",
};
//
// init
//
/// --- tmp ---
extern "C" void
reload_conf();
namespace ircd::m::init
{
struct modules;
}
namespace ircd::m
{
std::unique_ptr<dbs::init> _dbs;
std::unique_ptr<fetch::init> _fetch;
//std::unique_ptr<init::modules> _modules;
}
/// --- /tmp ---
void
ircd::m::on_load()
try
{
assert(ircd::run::level == run::level::START);
//reload_conf();
_fetch = std::make_unique<fetch::init>();
//_modules = std::make_unique<init::modules>();
//self::signon();
}
catch(const m::error &e)
{
log::error
{
log, "Failed to start matrix (%u) %s :%s :%s",
uint(e.code),
http::status(e.code),
e.errcode(),
e.errstr(),
};
throw;
}
catch(const std::exception &e)
{
log::error
{
log, "Failed to start matrix :%s", e.what()
};
throw;
}
void
ircd::m::on_unload()
noexcept try
{
//mods::imports.erase("m_listen"s);
if(m::sync::pool.size())
m::sync::pool.join();
//self::signoff();
_fetch.reset(nullptr);
//_modules.reset(nullptr);
//TODO: remove this for non-interfering shutdown
//server::interrupt_all();
//client::terminate_all();
//client::close_all();
//server::close_all();
//server::wait_all();
//client::wait_all();
}
catch(const m::error &e)
{
log::critical
{
log, "%s %s", e.what(), e.content
};
ircd::terminate();
}
//
// init::modules
//
/*
ircd::m::init::modules::modules()
{
const unwind::exceptional unload{[this]
{
this->fini_imports();
}};
init_imports();
}
ircd::m::init::modules::~modules()
noexcept
{
fini_imports();
}
void
ircd::m::init::modules::init_imports()
{
if(!bool(ircd::mods::autoload))
{
log::warning
{
"Not loading modules because noautomod flag is set. "
"You may still load modules manually."
};
return;
}
for(const auto &name : module_names) try
{
mods::imports.emplace(name, name);
}
catch(...)
{
const auto &optional(module_names_optional);
if(std::count(begin(optional), end(optional), name))
continue;
throw;
}
if(vm::sequence::retired == 0)
{
log::notice
{
log, "This appears to be your first time running IRCd because the events "
"database is empty. I will be bootstrapping it with initial events now..."
};
m::init::bootstrap{};
}
}
void
ircd::m::init::modules::fini_imports()
noexcept
{
for(auto it(module_names.rbegin()); it != module_names.rend(); ++it)
mods::imports.erase(*it);
}
*/

View file

@ -123,7 +123,7 @@ ircd::m::create(const node &node,
node.room_id()
};
create(room_id, m::me.user_id);
create(room_id, me());
return node;
}

View file

@ -99,11 +99,29 @@ const
thread_local char x_matrix[2_KiB];
if(startswith(json::at<"uri"_>(*this), "/_matrix/federation"))
{
const auto &sk{self::secret_key};
const auto &pkid{self::public_key_id};
const json::string &origin
{
json::at<"origin"_>(*this)
};
const auto &my
{
m::my(origin)
};
const auto &secret_key
{
m::secret_key(my)
};
const auto &public_key_id
{
m::public_key_id(my)
};
header[headers++] =
{
"Authorization", generate(x_matrix, sk, pkid)
"Authorization", generate(x_matrix, secret_key, public_key_id)
};
}
@ -169,14 +187,19 @@ const
stringify(mutable_buffer{buf}, *this)
};
const ed25519::sig sig
const json::string &origin
{
self::secret_key.sign(object)
json::at<"origin"_>(*this)
};
const auto &origin
const auto &secret_key
{
unquote(string_view{json::at<"origin"_>(*this)})
m::secret_key(my(origin))
};
const ed25519::sig sig
{
secret_key.sign(object)
};
thread_local char sigb64[1_KiB];

View file

@ -212,9 +212,14 @@ ircd::m::authenticate_user(const resource::method &method,
m::event::keys::include {"sender"}
};
const m::room::id::buf tokens_room
{
"tokens", origin(my())
};
const m::room::state tokens
{
m::user::tokens, &fopts
tokens_room, &fopts
};
tokens.get(std::nothrow, "ircd.access_token", request.access_token, [&request]

View file

@ -107,7 +107,7 @@ ircd::m::event::id::buf
ircd::m::notice(const room &room,
const string_view &body)
{
return message(room, me.user_id, body, "m.notice");
return message(room, me(), body, "m.notice");
}
ircd::m::event::id::buf
@ -744,7 +744,12 @@ ircd::m::local_joined(const room &room)
room
};
return !members.empty("join", my_host());
return !for_each([&members]
(const homeserver &homeserver)
{
// return false to break and return false; true to continue
return members.empty("join", origin(homeserver));
});
}
/// Member(s) from another server are presently joined to the room. For example
@ -848,7 +853,7 @@ ircd::m::internal(const id::room &room_id)
if(!exists(room))
return false;
if(!creator(room, m::me))
if(!creator(room, me()))
return false;
return true;
@ -868,7 +873,7 @@ ircd::m::exists(const id::room &room_id)
if(likely(it.depth() < 2UL))
return true;
if(my_host(room_id.host()) && creator(room_id, m::me))
if(my_host(room_id.host()) && creator(room_id, me()))
return true;
return false;

View file

@ -12,22 +12,8 @@ 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
{
@ -168,6 +154,16 @@ ircd::m::room::aliases::cache::del(const alias &alias)
make_key(buf, alias)
};
const m::room::id::buf alias_room_id
{
"alias", origin(my())
};
const m::room alias_room
{
alias_room_id
};
const auto &event_idx
{
alias_room.get(std::nothrow, "ircd.room.alias", key)
@ -186,7 +182,7 @@ ircd::m::room::aliases::cache::del(const alias &alias)
const auto ret
{
redact(alias_room, m::me.user_id, event_id, "deleted")
redact(alias_room, me(), event_id, "deleted")
};
return true;
@ -203,9 +199,19 @@ ircd::m::room::aliases::cache::set(const alias &alias,
make_key(buf, alias)
};
const m::room::id::buf alias_room_id
{
"alias", origin(my())
};
const m::room alias_room
{
alias_room_id
};
const auto ret
{
send(alias_room, m::me.user_id, "ircd.room.alias", key,
send(alias_room, me(), "ircd.room.alias", key,
{
{ "room_id", id }
})
@ -427,9 +433,14 @@ IRCD_MODULE_EXPORT
ircd::m::room::aliases::cache::for_each(const string_view &server,
const closure_bool &closure)
{
const m::room::id::buf alias_room_id
{
"alias", origin(my())
};
const m::room::state state
{
alias_room
alias_room_id
};
bool ret{true};
@ -574,6 +585,16 @@ ircd::m::room::aliases::cache::getidx(const alias &alias)
tolower(buf, swapped)
};
const m::room::id::buf alias_room_id
{
"alias", origin(my())
};
const m::room alias_room
{
alias_room_id
};
const auto &event_idx
{
alias_room.get(std::nothrow, "ircd.room.alias", key)

View file

@ -13,16 +13,9 @@ namespace ircd::m::rooms::summary
static void chunk_remote(const room &, json::stack::object &o);
static void chunk_local(const room &, json::stack::object &o);
extern const room::id::buf public_room_id;
extern hookfn<vm::eval &> create_public_room;
}
decltype(ircd::m::rooms::summary::public_room_id)
ircd::m::rooms::summary::public_room_id
{
"public", ircd::my_host()
};
/// Create the public rooms room during initial database bootstrap.
/// This hooks the creation of the !ircd room which is a fundamental
/// event indicating the database has just been created.
@ -34,9 +27,19 @@ ircd::m::rooms::summary::create_public_room
{ "room_id", "!ircd" },
{ "type", "m.room.create" },
},
[](const m::event &, m::vm::eval &)
[](const m::event &event, m::vm::eval &)
{
m::create(public_room_id, m::me.user_id);
auto &my
{
m::my(at<"origin"_>(event))
};
const auto &public_room_id
{
*my.rooms.emplace("public", origin(my)).first
};
m::create(public_room_id, me());
}
};
@ -140,6 +143,11 @@ IRCD_MODULE_EXPORT
ircd::m::rooms::summary::del(const m::room &room,
const string_view &origin)
{
const m::room::id::buf public_room_id
{
"public", my_host()
};
const m::room::state state
{
public_room_id
@ -164,7 +172,7 @@ ircd::m::rooms::summary::del(const m::room &room,
m::event_id(event_idx)
};
return redact(public_room_id, m::me, event_id, "delisted");
return redact(public_room_id, me(), event_id, "delisted");
}
ircd::m::event::id::buf
@ -197,13 +205,19 @@ ircd::m::rooms::summary::set(const m::room::id &room_id,
const string_view &origin,
const json::object &summary)
{
const m::room::id::buf public_room_id
{
"public", my_host()
};
char state_key_buf[event::STATE_KEY_MAX_SIZE];
const auto state_key
{
make_state_key(state_key_buf, room_id, origin)
};
return send(public_room_id, m::me, "ircd.rooms.summary", state_key, summary);
return send(public_room_id, me(), "ircd.rooms.summary", state_key, summary);
}
ircd::json::object
@ -275,6 +289,11 @@ IRCD_MODULE_EXPORT
ircd::m::rooms::summary::for_each(const room::id &room_id,
const closure_idx &closure)
{
const m::room::id::buf public_room_id
{
"public", my_host()
};
const m::room::state state
{
public_room_id

View file

@ -1,215 +0,0 @@
// 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.
std::string
ircd::m::self::origin
{
ircd::string_view{ircd::network_name}
};
std::string
ircd::m::self::servername
{
ircd::string_view{ircd::server_name}
};
ircd::ed25519::sk
ircd::m::self::secret_key
{};
ircd::ed25519::pk
ircd::m::self::public_key
{};
std::string
ircd::m::self::public_key_b64
{};
std::string
ircd::m::self::public_key_id
{};
std::string
ircd::m::self::tls_cert_der
{};
std::string
ircd::m::self::tls_cert_der_sha256_b64
{};
//
// my user
//
ircd::m::user::id::buf
ircd_user_id
{
"ircd", ircd::my_host()
};
ircd::m::user
ircd::m::me
{
ircd_user_id
};
//
// my room
//
ircd::m::room::id::buf
ircd_room_id
{
"ircd", ircd::my_host()
};
ircd::m::room
ircd::m::my_room
{
ircd_room_id
};
//
// my node
//
ircd::m::node
ircd::m::my_node
{
ircd::my_host()
};
//
// signon/signoff greetings
//
ircd::conf::item<std::string>
me_online_status_msg
{
{ "name", "ircd.me.online.status_msg" },
{ "default", "Wanna chat? IRCd at your service!" }
};
ircd::conf::item<std::string>
me_offline_status_msg
{
{ "name", "ircd.me.offline.status_msg" },
{ "default", "Catch ya on the flip side..." }
};
void
ircd::m::self::signon()
{
if(!ircd::write_avoid && vm::sequence::retired != 0)
presence::set(me, "online", me_online_status_msg);
}
void
ircd::m::self::signoff()
{
if(!std::uncaught_exceptions() && !ircd::write_avoid)
presence::set(me, "offline", me_offline_status_msg);
}
bool
ircd::m::self::host(const string_view &other)
{
// port() is 0 when the origin has no port (and implies 8448)
const auto port
{
net::port(hostport(origin))
};
// If my_host has a port number, then the argument must also have the
// same port number.
if(port)
return host() == other;
/// If my_host has no port number, then the argument can have port
/// 8448 or no port number, which will initialize net::hostport.port to
/// the "canon_port" of 8448.
assert(net::canon_port == 8448);
const net::hostport _other{other};
if(net::port(_other) != net::canon_port)
return false;
if(host() != host(_other))
return false;
return true;
}
ircd::string_view
ircd::m::self::host()
{
return m::self::origin;
}
//
// init
//
/// ID of the room which stores ephemeral tokens (an instance of the room is
/// provided below).
ircd::m::room::id::buf
tokens_room_id
{
"tokens", ircd::my_host()
};
/// The tokens room serves as a key-value lookup for various tokens to
/// users, etc. It primarily serves to store access tokens for users. This
/// is a separate room from the users room because in the future it may
/// have an optimized configuration as well as being more easily cleared.
///
ircd::m::room
ircd::m::user::tokens
{
tokens_room_id
};
ircd::m::self::init::init()
try
{
// Sanity check that these are valid hostname strings. This was likely
// already checked, so these validators will simply throw without very
// useful error messages if invalid strings ever make it this far.
rfc3986::valid_host(origin);
rfc3986::valid_host(servername);
ircd_user_id = {"ircd", origin};
m::me = {ircd_user_id};
ircd_room_id = {"ircd", origin};
m::my_room = {ircd_room_id};
if(origin == "localhost")
log::warning
{
"The origin is configured or has defaulted to 'localhost'"
};
}
catch(const std::exception &e)
{
log::critical
{
m::log, "Failed to init self origin[%s] servername[%s]",
origin,
servername,
};
throw;
}
static const auto self_init{[]
{
ircd::m::self::init();
return true;
}()};

View file

@ -67,7 +67,7 @@ ircd::m::create_user_room(const user::id &user_id,
const json::members &contents)
try
{
return create(room_id, m::me.user_id, "user");
return create(room_id, me(), "user");
}
catch(const std::exception &e)
{
@ -115,16 +115,26 @@ const
char b58[size(hash) * 2];
return
{
buf, b58encode(b58, hash), my_host()
buf, b58encode(b58, hash), origin(my())
};
}
ircd::m::device::id::buf
ircd::m::user::get_device_from_access_token(const string_view &token)
{
const m::room::id::buf tokens_room_id
{
"tokens", origin(my())
};
const m::room tokens
{
tokens_room_id
};
const event::idx event_idx
{
user::tokens.get("ircd.access_token", token)
tokens.get("ircd.access_token", token)
};
device::id::buf ret;

View file

@ -45,7 +45,7 @@ const
// specified. TODO: isn't that guest reg?
const m::id::user::buf user_id
{
username, my_host()
username, origin(my())
};
// Check if the the user_id is acceptably formed for this server or throws
@ -155,9 +155,14 @@ const
json::STRING
};
const m::room::id::buf user_tokens
{
"tokens", user_id.host()
};
const m::event::id::buf access_token_id
{
m::send(m::user::tokens, user_id, "ircd.access_token", access_token, json::members
m::send(user_tokens, user_id, "ircd.access_token", access_token, json::members
{
{ "ip", last_seen_ip },
{ "device_id", device_id },

View file

@ -43,7 +43,7 @@ void
ircd::m::app::init()
{
if(!m::exists(app_room_id))
m::create(app_room_id, m::me, "internal");
m::create(app_room_id, me(), "internal");
init_apps();
}

View file

@ -39,7 +39,7 @@ activate__user(const m::user &user)
user
};
return send(user_room, m::me.user_id, "ircd.account", "active", json::members
return send(user_room, m::me(), "ircd.account", "active", json::members
{
{ "value", true }
});

View file

@ -74,7 +74,7 @@ deactivate__user(const m::user &user,
user
};
return send(user_room, m::me.user_id, "ircd.account", "active", json::members
return send(user_room, m::me(), "ircd.account", "active", json::members
{
{ "value", false }
});

View file

@ -110,12 +110,17 @@ post__login_password(client &client,
string(remote_buf, remote(client)), json::STRING
};
const m::room::id::buf tokens_room
{
"tokens", origin(m::my())
};
// Log the user in by issuing an event in the tokens room containing
// the generated token. When this call completes without throwing the
// access_token will be committed and the user will be logged in.
const m::event::id::buf access_token_id
{
m::send(m::user::tokens, user_id, "ircd.access_token", access_token,
m::send(tokens_room, user_id, "ircd.access_token", access_token,
{
{ "ip", last_seen_ip },
{ "device_id", device_id },

View file

@ -76,9 +76,14 @@ post__logout(client &client,
request.access_token
};
const m::room::id::buf tokens_room_id
{
"tokens", origin(m::my())
};
const m::room::state tokens
{
m::user::tokens
tokens_room_id
};
const auto token_event_idx
@ -98,9 +103,14 @@ m::resource::response
post__logout_all(client &client,
const m::resource::request &request)
{
const m::room::id::buf tokens_room_id
{
"tokens", origin(m::my())
};
const m::room::state tokens
{
m::user::tokens
tokens_room_id
};
long count(0);
@ -145,9 +155,14 @@ try
m::event_id(token_event_idx)
};
const m::room::id::buf tokens_room_id
{
"tokens", origin(m::my())
};
const auto redaction_event_id
{
m::redact(m::user::tokens, user_id, token_event_id, reason)
m::redact(tokens_room_id, user_id, token_event_id, reason)
};
return true;

View file

@ -14,12 +14,6 @@ using namespace ircd;
static void create_report_room(const m::event &, m::vm::eval &);
const m::room::id::buf
report_room_id
{
"abuse", m::my_host()
};
conf::item<size_t>
reason_max
{
@ -78,6 +72,11 @@ post__report(client &client,
request.at("reason")
};
const m::room::id::buf report_room_id
{
"abuse", request.user_id.host()
};
const m::room room
{
report_room_id
@ -104,16 +103,26 @@ post__report(client &client,
}
void
create_report_room(const m::event &,
create_report_room(const m::event &event,
m::vm::eval &)
try
{
const auto &origin
{
at<"origin"_>(event)
};
const m::room::id::buf report_room_id
{
"abuse", origin
};
if(m::exists(report_room_id))
return;
const m::room room
{
m::create(report_room_id, m::me, "internal")
m::create(report_room_id, m::my(origin).self, "internal")
};
log::debug
@ -126,8 +135,7 @@ catch(const std::exception &e)
{
log::critical
{
m::log, "Creating the '%s' room failed :%s",
string_view{report_room_id},
m::log, "Creating the !abuse room failed :%s",
e.what()
};
}

View file

@ -67,7 +67,7 @@ ircd::m::sync::room_timeline_linear(data &data)
{
*data.room == data.user_room &&
startswith(json::get<"type"_>(*data.event), "ircd.cmd") &&
(json::get<"sender"_>(*data.event) == m::me.user_id ||
(json::get<"sender"_>(*data.event) == me() ||
json::get<"sender"_>(*data.event) == data.user.user_id)
};

View file

@ -1688,7 +1688,7 @@ console_cmd__conf__set(opt &out, const string_view &line)
const auto event_id
{
set_conf_item(m::me, key, val)
set_conf_item(m::me(), key, val)
};
out << event_id << " <- " << key << " = " << val << std::endl;
@ -5506,9 +5506,14 @@ console_cmd__net__listen(opt &out, const string_view &line)
for(const auto &[name, prop] : addl)
opts = insert(opts, json::member(name, prop));
const m::room::id::buf my_room
{
"ircd", origin(m::my())
};
const auto eid
{
m::send(m::my_room, m::me, "ircd.listen", token.at("name"), opts)
m::send(my_room, m::me(), "ircd.listen", token.at("name"), opts)
};
out << eid << std::endl;
@ -5523,9 +5528,19 @@ console_cmd__net__listen__del(opt &out, const string_view &line)
"name"
}};
const m::room::id::buf my_room_id
{
"ircd", origin(m::my())
};
const m::room my_room
{
my_room_id
};
const auto event_idx
{
m::my_room.get("ircd.listen", token.at("name"))
my_room.get("ircd.listen", token.at("name"))
};
const auto event_id
@ -5535,7 +5550,7 @@ console_cmd__net__listen__del(opt &out, const string_view &line)
const auto redact_id
{
m::redact(m::my_room, m::me, event_id, "deleted")
m::redact(my_room, m::me(), event_id, "deleted")
};
out << "Removed listener '" << token.at("name") << "' configuration. " << std::endl
@ -5890,8 +5905,8 @@ console_cmd__key(opt &out, const string_view &line)
if(!server_name)
{
out << "origin: " << m::my_host() << std::endl;
out << "public key ID: " << m::self::public_key_id << std::endl;
out << "public key base64: " << m::self::public_key_b64 << std::endl;
out << "public key ID: " << m::public_key_id(m::my()) << std::endl;
//out << "public key base64: " << m::self::public_key_b64 << std::endl;
return true;
}
@ -5950,14 +5965,6 @@ console_cmd__key__get(opt &out, const string_view &line)
return true;
}
bool
console_cmd__key__create(opt &out, const string_view &line)
{
m::self::create_my_key();
out << "done" << std::endl;
return true;
}
//
// stage
//
@ -6008,6 +6015,11 @@ console_cmd__stage(opt &out, const string_view &line)
key? tokens_after(line, ' ', 1) : string_view{}
};
const m::room::id::buf my_room
{
"ircd", origin(m::my())
};
if(stage.size() == id)
{
m::event base_event{json::members
@ -6015,8 +6027,8 @@ console_cmd__stage(opt &out, const string_view &line)
{ "depth", json::undefined_number },
{ "origin", my_host() },
{ "origin_server_ts", time<milliseconds>() },
{ "sender", m::me.user_id },
{ "room_id", m::my_room.room_id },
{ "sender", m::me() },
{ "room_id", my_room },
{ "type", "m.room.message" },
{ "prev_state", "[]" },
}};
@ -10332,7 +10344,7 @@ console_cmd__room__create(opt &out, const string_view &line)
const m::user::id creator
{
param.at(1, m::me.user_id)
param.at(1, m::me())
};
const string_view type
@ -10976,7 +10988,7 @@ console_cmd__user__read__ignore(opt &out, const string_view &line)
const auto eid
{
send(user_room, m::me.user_id, "ircd.read.ignore", target, json::object{})
send(user_room, m::me(), "ircd.read.ignore", target, json::object{})
};
out << "User " << my_user.user_id << " will not send receipts for"
@ -11170,9 +11182,14 @@ console_cmd__user__tokens(opt &out, const string_view &line)
param["clear"] == "clear"
};
const m::room::id::buf tokens_room
{
"tokens", origin(m::my())
};
const m::room::state &tokens
{
m::user::tokens
tokens_room
};
tokens.for_each("ircd.access_token", m::event::closure_idx{[&out, &user, &clear]
@ -11216,12 +11233,16 @@ console_cmd__user__tokens(opt &out, const string_view &line)
<< " "
<< string_view{event.event_id};
if(clear)
{
const m::room::id::buf tokens_room
{
"tokens", origin(m::my())
};
const auto eid
{
m::redact(m::user::tokens, user.user_id, event.event_id, "cleared")
m::redact(tokens_room, user.user_id, event.event_id, "cleared")
};
out << " - cleared by " << eid;
@ -12079,7 +12100,7 @@ console_cmd__feds__heads(opt &out, const string_view &line)
const m::user::id &user_id
{
param.at(1, m::me.user_id)
param.at(1, m::me())
};
using closure_prototype = bool (const string_view &,
@ -13863,7 +13884,7 @@ console_cmd__file__download(opt &out, const string_view &line)
const auto room_id
{
m::media::file::download(mxc, m::me.user_id, remote)
m::media::file::download(mxc, m::me(), remote)
};
out << room_id << std::endl;

View file

@ -113,7 +113,7 @@ try
const auto &response_sender
{
public_response? user : m::me
public_response? user : m::user(m::me())
};
const auto &response_room

View file

@ -100,7 +100,7 @@ noexcept try
"no alt text"
};
msghtml(control_room, m::me.user_id, str, alt, "m.notice");
msghtml(control_room, m::me(), str, alt, "m.notice");
}
catch(const std::exception &e)
{
@ -127,15 +127,15 @@ static void
create_control_room(const m::event &,
m::vm::eval &)
{
create(control_room_id, m::me.user_id);
join(control_room, m::me.user_id);
send(control_room, m::me.user_id, "m.room.name", "",
create(control_room_id, m::me());
join(control_room, m::me());
send(control_room, m::me(), "m.room.name", "",
{
{ "name", "Control Room" }
});
notice(control_room, m::me.user_id, "Welcome to the control room.");
notice(control_room, m::me.user_id, "I am the daemon. You can talk to me in this room by highlighting me.");
notice(control_room, m::me(), "Welcome to the control room.");
notice(control_room, m::me(), "I am the daemon. You can talk to me in this room by highlighting me.");
}
m::hookfn<m::vm::eval &>

View file

@ -56,6 +56,11 @@ ircd::m::_access_token_delete(const m::event &event,
unquote(content.at(""))
};
m::redact(m::user::tokens, at<"sender"_>(event), token_event_id, "device deleted");
const m::room::id::buf tokens_room
{
"tokens", origin(m::my())
};
m::redact(tokens_room, at<"sender"_>(event), token_event_id, "device deleted");
});
};

View file

@ -104,8 +104,17 @@ on_quit()
void
init_listeners()
{
m::room::state{m::my_room}.for_each("ircd.listen", []
(const m::event &event)
const m::room::id::buf my_room
{
"ircd", m::origin(m::my())
};
const m::room::state state
{
my_room
};
state.for_each("ircd.listen", [](const m::event &event)
{
load_listener(event);
});
@ -150,7 +159,16 @@ load_listener(const string_view &name)
try
{
bool ret{false};
const m::room::state state{m::my_room};
const m::room::id::buf my_room
{
"ircd", m::origin(m::my())
};
const m::room::state state
{
my_room
};
state.get("ircd.listen", name, [&ret]
(const m::event &event)
{

View file

@ -28,18 +28,6 @@ IRCD_MODULE
"Matrix m.room.aliases"
};
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
};
//
// create the alias room as an effect of !ircd created on bootstrap
//
@ -53,9 +41,19 @@ ircd::m::create_alias_room_hookfn
{ "type", "m.room.create" },
},
[](const m::event &, m::vm::eval &)
[](const m::event &event, m::vm::eval &)
{
create(alias_room_id, m::me.user_id);
auto &my
{
m::my(at<"origin"_>(event))
};
const auto &alias_room_id
{
*my.rooms.emplace("alias", origin(my)).first
};
create(alias_room_id, my.self);
}
};

View file

@ -49,7 +49,7 @@ try
const auto &level
{
my(sender) && sender != m::me?
my(sender) && sender != me()?
log::INFO:
log::DEBUG
};

View file

@ -135,7 +135,7 @@ ircd::m::vm::init()
log::info
{
log, "BOOT %s @%lu [%s] db:%lu",
string_view{m::my_node.node_id},
server_name(my()),
sequence::retired,
sequence::retired?
string_view{event_id} : "NO EVENTS"_sv,
@ -175,7 +175,7 @@ ircd::m::vm::fini()
log::info
{
log, "HALT '%s' @%lu [%s] vm:%lu:%lu:%lu db:%lu",
string_view{m::my_node.node_id},
server_name(my()),
retired,
retired?
string_view{event_id} : "NO EVENTS"_sv,

View file

@ -65,7 +65,7 @@ get__download(client &client,
{
request.user_id?
m::user::id{request.user_id}:
m::me.user_id
m::me()
};
const bool allow_remote

View file

@ -122,7 +122,7 @@ get__thumbnail(client &client,
{
request.user_id?
m::user::id{request.user_id}:
m::me.user_id
m::me()
};
if(!m::media::thumbnail::enable_remote)

View file

@ -172,7 +172,7 @@ try
rr0.~object();
array.~array();
content.~object();
send(room_id, m::me, type, state_key, json::object(out.completed()));
send(room_id, m::me(), type, state_key, json::object(out.completed()));
return true;
}
catch(const http::error &e)
@ -297,7 +297,7 @@ try
array.~array();
content.~object();
send(room_id, m::me, type, state_key, json::object{out.completed()});
send(room_id, m::me(), type, state_key, json::object{out.completed()});
return true;
}
catch(const http::error &e)
@ -695,7 +695,7 @@ try
{
const m::room room
{
m::create(room_id, m::me, "internal")
m::create(room_id, m::me(), "internal")
};
log::debug

View file

@ -80,7 +80,7 @@ handle_matrix_server(client &client,
{
client, json::members
{
{ "m.server", m::self::servername }
{ "m.server", m::server_name(m::my()) }
}
};
}