mirror of
https://github.com/matrix-construct/construct
synced 2024-11-26 00:32:35 +01:00
ircd:Ⓜ️:vm: Add redacted canonization cases prior to eval.
This commit is contained in:
parent
be7bab0c16
commit
d49227c848
5 changed files with 102 additions and 53 deletions
|
@ -95,6 +95,7 @@ struct ircd::m::vm::eval
|
|||
hook::base *hook {nullptr};
|
||||
vm::phase phase {vm::phase(0)};
|
||||
bool room_internal {false};
|
||||
bool redacted {false};
|
||||
|
||||
void mfetch_keys() const;
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ ircd::m::vm::conform_report
|
|||
[](const m::event &event, eval &eval)
|
||||
{
|
||||
assert(eval.opts);
|
||||
auto &opts(*eval.opts);
|
||||
const auto &opts(*eval.opts);
|
||||
|
||||
// When opts.conformed is set the report is already generated
|
||||
if(opts.conformed)
|
||||
|
@ -124,17 +124,30 @@ ircd::m::vm::conform_report
|
|||
return;
|
||||
}
|
||||
|
||||
// Mask of checks to be bypassed
|
||||
auto non_conform
|
||||
{
|
||||
opts.non_conform
|
||||
};
|
||||
|
||||
// This hook is called prior to event_id determination; must be skipped
|
||||
non_conform.set(event::conforms::INVALID_OR_MISSING_EVENT_ID);
|
||||
|
||||
// For internal rooms for now.
|
||||
if(eval.room_internal)
|
||||
non_conform.set(event::conforms::MISMATCH_ORIGIN_SENDER);
|
||||
|
||||
// Generate the report here.
|
||||
eval.report = event::conforms
|
||||
{
|
||||
event, opts.non_conform.report
|
||||
event, non_conform.report
|
||||
};
|
||||
|
||||
// When opts.conforming is false a bad report is not an error.
|
||||
if(!opts.conforming)
|
||||
return;
|
||||
|
||||
const bool redacted
|
||||
eval.redacted =
|
||||
{
|
||||
// redacted hint given in options
|
||||
opts.redacted != -1?
|
||||
|
@ -149,24 +162,33 @@ ircd::m::vm::conform_report
|
|||
false:
|
||||
|
||||
// assume redacted when hash mismatch already allowed
|
||||
(opts.non_conform.has(event::conforms::MISMATCH_HASHES))?
|
||||
non_conform.has(event::conforms::MISMATCH_HASHES)?
|
||||
true:
|
||||
|
||||
// assume no redaction for hash match
|
||||
(!eval.report.has(event::conforms::MISMATCH_HASHES))?
|
||||
!eval.report.has(event::conforms::MISMATCH_HASHES)?
|
||||
false:
|
||||
|
||||
// case for authoritative redaction
|
||||
eval.report.has(event::conforms::MISMATCH_HASHES)
|
||||
&& opts.node_id == json::get<"origin"_>(event)?
|
||||
true:
|
||||
|
||||
// make query
|
||||
bool(m::redacted(event.event_id))
|
||||
event.event_id?
|
||||
bool(m::redacted(event.event_id)):
|
||||
|
||||
// otherwise deny redacted
|
||||
false
|
||||
};
|
||||
|
||||
auto report
|
||||
{
|
||||
eval.report
|
||||
};;
|
||||
};
|
||||
|
||||
// Allow content hash to fail on redacted events.
|
||||
if(redacted)
|
||||
if(eval.redacted)
|
||||
report.del(event::conforms::MISMATCH_HASHES);
|
||||
|
||||
// Otherwise this will kill the eval
|
||||
|
|
|
@ -328,7 +328,7 @@ ircd::m::commit(const room &room,
|
|||
// Some functionality on this server may create an event on behalf
|
||||
// of remote users. It's safe for us to mask this here, but eval'ing
|
||||
// this event in any replay later will require special casing.
|
||||
opts.non_conform |= event::conforms::MISMATCH_ORIGIN_SENDER;
|
||||
opts.non_conform.set(event::conforms::MISMATCH_ORIGIN_SENDER);
|
||||
|
||||
// Don't need this here
|
||||
opts.phase.reset(vm::phase::VERIFY);
|
||||
|
|
|
@ -218,32 +218,16 @@ try
|
|||
*eval.opts
|
||||
};
|
||||
|
||||
assert(!eval.buf || size(eval.buf) >= event::MAX_SIZE);
|
||||
if(!opts.json_source && !eval.buf)
|
||||
eval.buf = unique_mutable_buffer
|
||||
{
|
||||
event::MAX_SIZE, 64
|
||||
};
|
||||
|
||||
const scope_restore event_source
|
||||
const scope_restore eval_report
|
||||
{
|
||||
mutable_cast(event).source,
|
||||
|
||||
// Canonize from some other serialized source.
|
||||
!opts.json_source && event.source?
|
||||
json::object(json::stringify(mutable_buffer{eval.buf}, event.source)):
|
||||
|
||||
// Canonize from no source; usually taken when my(event).
|
||||
// XXX elision conditions go here
|
||||
!opts.json_source?
|
||||
json::object(json::stringify(mutable_buffer{eval.buf}, event)):
|
||||
|
||||
// Use the input directly.
|
||||
event.source
|
||||
eval.report, event::conforms{}
|
||||
};
|
||||
|
||||
const scope_restore eval_redacted
|
||||
{
|
||||
eval.redacted, false
|
||||
};
|
||||
|
||||
// Set a member to the room_id for convenient access, without stepping on
|
||||
// any room_id reference that exists there for whatever reason.
|
||||
const scope_restore eval_room_id
|
||||
{
|
||||
eval.room_id,
|
||||
|
@ -253,7 +237,7 @@ try
|
|||
eval.room_id:
|
||||
|
||||
// Use the room_id in the event
|
||||
likely(valid(id::ROOM, json::get<"room_id"_>(event)))?
|
||||
likely(json::get<"room_id"_>(event))?
|
||||
string_view(json::get<"room_id"_>(event)):
|
||||
|
||||
eval.room_id,
|
||||
|
@ -288,6 +272,68 @@ try
|
|||
false
|
||||
};
|
||||
|
||||
// These checks only require the event data itself.
|
||||
if(likely(opts.phase[phase::CONFORM]) && !opts.edu)
|
||||
{
|
||||
const scope_restore eval_phase
|
||||
{
|
||||
eval.phase, phase::CONFORM
|
||||
};
|
||||
|
||||
const ctx::critical_assertion ca;
|
||||
call_hook(conform_hook, eval, event, eval);
|
||||
}
|
||||
|
||||
assert(!eval.buf || size(eval.buf) >= event::MAX_SIZE);
|
||||
const bool redacted
|
||||
{
|
||||
eval.redacted
|
||||
|| eval.report.has(event::conforms::MISMATCH_HASHES)
|
||||
};
|
||||
|
||||
if(!opts.edu && !eval.buf && (!opts.json_source || redacted))
|
||||
eval.buf = unique_mutable_buffer
|
||||
{
|
||||
event::MAX_SIZE, 64
|
||||
};
|
||||
|
||||
const scope_restore event_source
|
||||
{
|
||||
mutable_cast(event).source,
|
||||
|
||||
// Canonize and redact from some other serialized source.
|
||||
!opts.edu && !opts.json_source && event.source && redacted?
|
||||
json::stringify(mutable_buffer{eval.buf}, m::essential(event.source, event::buf[0])):
|
||||
|
||||
// Canonize and redact from no source.
|
||||
!opts.edu && !opts.json_source && redacted?
|
||||
json::stringify(mutable_buffer{eval.buf}, m::essential(event, event::buf[0])):
|
||||
|
||||
// Canonize from some other serialized source.
|
||||
likely(!opts.edu && !opts.json_source && event.source)?
|
||||
json::stringify(mutable_buffer{eval.buf}, event.source):
|
||||
|
||||
// Canonize from no source; usually taken when my(event).
|
||||
// XXX elision conditions go here
|
||||
likely(!opts.edu && !opts.json_source)?
|
||||
json::stringify(mutable_buffer{eval.buf}, event):
|
||||
|
||||
// Use the input directly.
|
||||
string_view{event.source}
|
||||
};
|
||||
|
||||
const scope_restore eval_room_id_reref
|
||||
{
|
||||
eval.room_id,
|
||||
|
||||
// Re-assigns reference after any prior rewrites
|
||||
likely(json::get<"room_id"_>(event))?
|
||||
string_view(json::get<"room_id"_>(event)):
|
||||
|
||||
// No action
|
||||
eval.room_id,
|
||||
};
|
||||
|
||||
// Procure the room version.
|
||||
char room_version_buf[room::VERSION_MAX_SIZE];
|
||||
const scope_restore eval_room_version
|
||||
|
@ -648,19 +694,6 @@ ircd::m::vm::execute_pdu(eval &eval,
|
|||
fault::GENERAL, "Internal room event denied from external source."
|
||||
};
|
||||
|
||||
// The conform hook runs static checks on an event's formatting and
|
||||
// composure; these checks only require the event data itself.
|
||||
if(likely(opts.phase[phase::CONFORM]))
|
||||
{
|
||||
const scope_restore eval_phase
|
||||
{
|
||||
eval.phase, phase::CONFORM
|
||||
};
|
||||
|
||||
const ctx::critical_assertion ca;
|
||||
call_hook(conform_hook, eval, event, eval);
|
||||
}
|
||||
|
||||
// Wait for any pending duplicate evals before proceeding.
|
||||
assert(eval::count(event_id));
|
||||
if(likely(opts.phase[phase::DUPCHK] && opts.unique))
|
||||
|
|
|
@ -349,7 +349,6 @@ try
|
|||
opts.warnlog &= ~vm::fault::EXISTS;
|
||||
opts.notify_servers = false;
|
||||
opts.node_id = origin;
|
||||
|
||||
log::debug
|
||||
{
|
||||
log, "Evaluating auth chain for %s in %s events:%zu",
|
||||
|
@ -475,12 +474,6 @@ try
|
|||
opts.phase.set(m::vm::phase::FETCH_STATE, false);
|
||||
opts.node_id = result.origin;
|
||||
opts.notify_servers = false;
|
||||
|
||||
// The result won't give us events with a content hash mismatch unless
|
||||
// they were obtained from an authoritative source. For this we can
|
||||
// unconditionally allow hash mismatch from here.
|
||||
opts.redacted = 1;
|
||||
|
||||
vm::eval
|
||||
{
|
||||
pdus, opts
|
||||
|
|
Loading…
Reference in a new issue