0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-06-10 14:08:56 +02:00

ircd:Ⓜ️:vm: Create a conform hook; move checks into conform hookfns.

This commit is contained in:
Jason Volk 2019-03-09 13:12:58 -08:00
parent e501c6434a
commit 197168059b
6 changed files with 113 additions and 70 deletions

View file

@ -21,8 +21,6 @@ namespace ircd::m
bool my(const event &);
size_t degree(const event &);
string_view membership(const event &);
bool check_size(std::nothrow_t, const event &);
void check_size(const event &);
// [GET]
bool exists(const id::event &);

View file

@ -52,6 +52,7 @@ struct ircd::m::vm::eval
const vm::opts *opts {&default_opts};
const vm::copts *copts {nullptr};
event::conforms report;
uint64_t sequence {0};
db::txn *txn {nullptr};
@ -113,6 +114,9 @@ enum ircd::m::vm::fault
/// Evaluation Options
struct ircd::m::vm::opts
{
/// Call conform hooks (detailed behavior can be tweaked below)
bool conform {true};
/// Make fetches or false to bypass fetch stage.
bool fetch {true};

View file

@ -2406,35 +2406,6 @@ ircd::m::exists(const id::event &event_id)
return has(column, event_id);
}
void
ircd::m::check_size(const event &event)
{
const size_t &event_size
{
serialized(event)
};
if(event_size > size_t(event::max_size))
throw m::BAD_JSON
{
"Event is %zu bytes which is larger than the maximum %zu bytes",
event_size,
size_t(event::max_size)
};
}
bool
ircd::m::check_size(std::nothrow_t,
const event &event)
{
const size_t &event_size
{
serialized(event)
};
return event_size <= size_t(event::max_size);
}
ircd::string_view
ircd::m::membership(const event &event)
{

View file

@ -55,6 +55,7 @@ handle_edu(client &client,
vmopts.non_conform.set(m::event::conforms::MISSING_ORIGIN_SIGNATURE);
vmopts.non_conform.set(m::event::conforms::MISSING_SIGNATURES);
vmopts.non_conform.set(m::event::conforms::MISSING_PREV_EVENTS);
vmopts.non_conform.set(m::event::conforms::MISSING_AUTH_EVENTS);
vmopts.non_conform.set(m::event::conforms::MISSING_PREV_STATE);
vmopts.non_conform.set(m::event::conforms::DEPTH_ZERO);
m::vm::eval eval

View file

@ -8,15 +8,101 @@
// 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::m;
using namespace ircd;
mapi::header
ircd::mapi::header
IRCD_MODULE
{
"Matrix event library; modular components."
};
namespace ircd::m::vm
{
extern const m::hookfn<eval &> issue_missing_auth;
extern const m::hookfn<eval &> conform_check_origin;
extern const m::hookfn<eval &> conform_check_size;
extern const m::hookfn<eval &> conform_report;
}
/// Check if an eval with a copts structure (indicating this server is
/// creating the event) has an origin set to !my_host().
decltype(ircd::m::vm::conform_check_origin)
ircd::m::vm::conform_check_origin
{
{
{ "_site", "vm.conform" }
},
[](const m::event &event, eval &eval)
{
if(unlikely(eval.copts && !my_host(at<"origin"_>(event))))
throw error
{
fault::GENERAL, "Issuing event for origin: %s", at<"origin"_>(event)
};
}
};
/// Check if an event originating from this server exceeds maximum size.
decltype(ircd::m::vm::conform_check_size)
ircd::m::vm::conform_check_size
{
{
{ "_site", "vm.conform" },
{ "origin", my_host() }
},
[](const m::event &event, eval &eval)
{
const size_t &event_size
{
serialized(event)
};
if(event_size > size_t(event::max_size))
throw m::BAD_JSON
{
"Event is %zu bytes which is larger than the maximum %zu bytes",
event_size,
size_t(event::max_size)
};
}
};
/// Check if an event originating from this server exceeds maximum size.
decltype(ircd::m::vm::conform_report)
ircd::m::vm::conform_report
{
{
{ "_site", "vm.conform" }
},
[](const m::event &event, eval &eval)
{
assert(eval.opts);
auto &opts(*eval.opts);
// When opts.conformed is set the report is already generated
if(opts.conformed)
{
eval.report = opts.report;
return;
}
// Generate the report here.
eval.report = event::conforms
{
event, opts.non_conform.report
};
// When opts.conforming is false a bad report is not an error.
if(!opts.conforming)
return;
// Otherwise this will kill the eval
if(!eval.report.clean())
throw error
{
fault::INVALID, "Non-conforming event: %s", string(eval.report)
};
}
};
std::ostream &
IRCD_MODULE_EXPORT
ircd::m::pretty(std::ostream &s,

View file

@ -25,9 +25,10 @@ namespace ircd::m::vm
static void init();
static void fini();
extern hook::site<eval &> issue_hook; ///< Called when this server issues event
extern hook::site<eval &> issue_hook; ///< Called when this server is issuing event
extern hook::site<eval &> conform_hook; ///< Called for static evaluations of event
extern hook::site<eval &> fetch_hook; ///< Called to resolve dependencies
extern hook::site<eval &> eval_hook; ///< Called when evaluating event
extern hook::site<eval &> eval_hook; ///< Called for final event evaluation
extern hook::site<eval &> post_hook; ///< Called to apply effects pre-notify
extern hook::site<eval &> notify_hook; ///< Called to broadcast successful eval
extern hook::site<eval &> effect_hook; ///< Called to apply effects post-notify
@ -63,6 +64,12 @@ ircd::m::vm::issue_hook
{ "name", "vm.issue" }
};
decltype(ircd::m::vm::conform_hook)
ircd::m::vm::conform_hook
{
{ "name", "vm.conform" }
};
decltype(ircd::m::vm::fetch_hook)
ircd::m::vm::fetch_hook
{
@ -448,47 +455,23 @@ try
assert(eval.event_);
assert(eval.id);
assert(eval.ctx);
const auto &opts
{
*eval.opts
};
if(eval.copts)
{
if(unlikely(!my_host(at<"origin"_>(event))))
throw error
{
fault::GENERAL, "Committing event for origin: %s", at<"origin"_>(event)
};
if(eval.copts->debuglog_precommit)
log::debug
{
log, "Injecting event %s", pretty_oneline(event)
};
check_size(event);
if(eval.copts->issue)
issue_hook(event, eval);
}
event::conforms report
{
opts.conforming && !opts.conformed?
event::conforms{event, opts.non_conform.report}:
opts.report
};
report.del(event::conforms::MISSING_AUTH_EVENTS);
if(opts.conforming && !report.clean())
throw error
if(eval.copts && eval.copts->debuglog_precommit)
log::debug
{
fault::INVALID, "Non-conforming event: %s", string(report)
log, "Issuing: %s", pretty_oneline(event)
};
if(eval.copts && eval.copts->issue)
issue_hook(event, eval);
if(opts.conform)
conform_hook(event, eval);
// A conforming (with lots of masks) event without an event_id is an EDU.
const fault ret
{