diff --git a/include/ircd/m/event/pretty.h b/include/ircd/m/event/pretty.h index e760dafaf..aa1a853a6 100644 --- a/include/ircd/m/event/pretty.h +++ b/include/ircd/m/event/pretty.h @@ -30,5 +30,5 @@ namespace ircd::m // Informational pretty for state // io=true will run db queries to enhance w/ more information. - std::ostream &pretty_stateline(std::ostream &, const event &, const event::id &rel = {}, const event::idx & = 0); + std::ostream &pretty_stateline(std::ostream &, const event &, const event::idx & = 0); } diff --git a/include/ircd/m/room/auth.h b/include/ircd/m/room/auth.h index dae8937cb..271171881 100644 --- a/include/ircd/m/room/auth.h +++ b/include/ircd/m/room/auth.h @@ -26,8 +26,12 @@ struct ircd::m::room::auth static bool is_power_event(const event &); - static passfail check(std::nothrow_t, const event &, hookdata &); - static passfail check(std::nothrow_t, const event &); + static passfail check(const event &, hookdata &); + static passfail check(const event &, const vector_view &); + static passfail check(const event &, const room &); + static passfail check_static(const event &); + static passfail check_present(const event &); + static passfail check_relative(const event &); static void check(const event &); static bool generate(json::stack::array &, const m::room &, const m::event &); diff --git a/modules/console.cc b/modules/console.cc index b8ba22928..394a01c1e 100644 --- a/modules/console.cc +++ b/modules/console.cc @@ -6732,11 +6732,28 @@ console_cmd__event(opt &out, const string_view &line) << "HASH MISMATCH :" << b64encode_unpadded(hash(event)) << std::endl; - const auto &[authed, failmsg](m::room::auth::check(std::nothrow, event)); - if(!authed) - out << std::setw(9) << std::left << "!!! ERROR" << " " - << "UNAUTHORIZED :" << what(failmsg) - << std::endl; + { + const auto &[authed, failmsg](m::room::auth::check_static(event)); + if(!authed) + out << std::setw(9) << std::left << "!!! ERROR" << " " + << "UNAUTHORIZED STATIC :" << what(failmsg) + << std::endl; + } + + { + const auto &[authed, failmsg](m::room::auth::check_present(event)); + if(!authed) + out << std::setw(9) << std::left << "!!! ERROR" << " " + << "PRESENTLY UNAUTHORIZED :" << what(failmsg) + << std::endl; + } + { + const auto &[authed, failmsg](m::room::auth::check_relative(event)); + if(!authed) + out << std::setw(9) << std::left << "!!! ERROR" << " " + << "RELATIVELY UNAUTHORIZED :" << what(failmsg) + << std::endl; + } try { @@ -7716,7 +7733,7 @@ console_cmd__room__top(opt &out, const string_view &line) out << "top auth:" << std::endl; ssize_t adi(auth.depth()); - auth.for_each([&room, &out, &adi] + auth.for_each([&out, &adi] (const m::event::idx &event_idx) { if(adi-- > 8) @@ -7728,7 +7745,7 @@ console_cmd__room__top(opt &out, const string_view &line) }; if(event.valid) - m::pretty_stateline(out, event, room.event_id, event_idx); + m::pretty_stateline(out, event, event_idx); return true; }); @@ -8811,7 +8828,7 @@ console_cmd__room__state(opt &out, const string_view &line) string_view{} }; - state.for_each(type, [&out, &state] + state.for_each(type, [&out] (const string_view &type, const string_view &state_key, const m::event::idx &event_idx) { const m::event::fetch event @@ -8822,7 +8839,7 @@ console_cmd__room__state(opt &out, const string_view &line) if(!event.valid) return true; - m::pretty_stateline(out, event, state.event_id, event_idx); + m::pretty_stateline(out, event, event_idx); /* size_t i(0); @@ -9071,7 +9088,7 @@ console_cmd__room__state__history(opt &out, const string_view &line) room, bound }; - history.for_each(type, state_key, [&out, &room] + history.for_each(type, state_key, [&out] (const auto &type, const auto &state_key, const auto &depth, const auto &event_idx) { const m::event::fetch event @@ -9082,7 +9099,7 @@ console_cmd__room__state__history(opt &out, const string_view &line) if(!event.valid) return true; - m::pretty_stateline(out, event, room.event_id, event_idx); + m::pretty_stateline(out, event, event_idx); return true; }); @@ -9129,7 +9146,7 @@ console_cmd__room__state__space(opt &out, const string_view &line) room_id }; - space.for_each(type, state_key, depth, [&out, &state] + space.for_each(type, state_key, depth, [&out] (const auto &type, const auto &state_key, const auto &depth, const auto &event_idx) { const m::event::fetch event @@ -9140,7 +9157,7 @@ console_cmd__room__state__space(opt &out, const string_view &line) if(!event.valid) return true; - m::pretty_stateline(out, event, {}, event_idx); + m::pretty_stateline(out, event, event_idx); return true; }); diff --git a/modules/m_event.cc b/modules/m_event.cc index 49d4ac9fe..5634fd4f3 100644 --- a/modules/m_event.cc +++ b/modules/m_event.cc @@ -23,12 +23,11 @@ std::ostream & IRCD_MODULE_EXPORT ircd::m::pretty_stateline(std::ostream &out, const event &event, - const event::id &rel, const event::idx &event_idx) { const room room { - json::get<"room_id"_>(event), rel?: event::id{} + json::get<"room_id"_>(event) }; const room::state &state @@ -55,23 +54,40 @@ ircd::m::pretty_stateline(std::ostream &out, m::room::auth::is_power_event(event) }; - const auto auth + const room::auth::passfail auth[] { event_idx? - room::auth::check(std::nothrow, event): - room::auth::passfail{true, {}} + room::auth::check_static(event): + room::auth::passfail{false, {}}, + + event_idx && m::exists(event.event_id)? + room::auth::check_relative(event): + room::auth::passfail{false, {}}, + + event_idx? + room::auth::check_present(event): + room::auth::passfail{false, {}}, }; - char buf[16]; + char buf[32]; const string_view flags { fmt::sprintf { - buf, "%c%c%c%c", - active? 'A' : ' ', - !std::get(auth)? 'F' : ' ', - power? 'P' : ' ', - redacted? 'R' : ' ', + buf, "%c%c%c|%c%c%c", + + active? 'A' : '-', + redacted? 'R' : '-', + power? 'P' : '-', + + std::get(auth[0]) && !std::get(auth[0])? ' ': + !std::get(auth[0]) && std::get(auth[0])? 'X': '?', + + std::get(auth[1]) && !std::get(auth[1])? ' ': + !std::get(auth[1]) && std::get(auth[1])? 'X': '?', + + std::get(auth[2]) && !std::get(auth[2])? ' ': + !std::get(auth[2]) && std::get(auth[2])? 'X': '?', } }; @@ -125,8 +141,8 @@ ircd::m::pretty_stateline(std::ostream &out, ; } - if(std::get<1>(auth)) - out << ":" << trunc(what(std::get<1>(auth)), 72); + if(std::get<1>(auth[0])) + out << ":" << trunc(what(std::get<1>(auth[0])), 72); out << std::endl; return out; diff --git a/modules/m_room_auth.cc b/modules/m_room_auth.cc index 3bd05485e..389603a65 100644 --- a/modules/m_room_auth.cc +++ b/modules/m_room_auth.cc @@ -144,23 +144,95 @@ void IRCD_MODULE_EXPORT ircd::m::room::auth::check(const event &event) { - const auto &[pass, fail] - { - check(std::nothrow, event) - }; + passfail pf; + auto &[pass, fail] {pf}; - if(!pass) + pf = check_static(event); + + if(!pass) try { assert(bool(fail)); std::rethrow_exception(fail); __builtin_unreachable(); } + catch(const FAIL &e) + { + throw FAIL + { + "Fails against provided auth_events :%s", e.what() + }; + } + + if(!m::exists(room(at<"room_id"_>(event)))) + if(at<"type"_>(event) == "m.room.create") + return; + + pf = check_present(event); + + if(!pass) try + { + assert(bool(fail)); + std::rethrow_exception(fail); + __builtin_unreachable(); + } + catch(const FAIL &e) + { + throw FAIL + { + "Fails against present state of %s :%s", + json::get<"room_id"_>(event), + e.what() + }; + } + + if(!m::exists(event.event_id)) + return; + + pf = check_relative(event); + + if(!pass) try + { + assert(bool(fail)); + std::rethrow_exception(fail); + __builtin_unreachable(); + } + catch(const FAIL &e) + { + throw FAIL + { + "Fails against state of %s relative to %s :%s", + json::get<"room_id"_>(event), + string_view{event.event_id}, + e.what() + }; + } } ircd::m::room::auth::passfail IRCD_MODULE_EXPORT -ircd::m::room::auth::check(std::nothrow_t, - const event &event) +ircd::m::room::auth::check_relative(const event &event) +try +{ + using json::at; + + const m::room room + { + at<"room_id"_>(event), event.event_id + }; + + return check(event, room); +} +catch(const std::exception &) +{ + return + { + false, std::current_exception() + }; +} + +ircd::m::room::auth::passfail +IRCD_MODULE_EXPORT +ircd::m::room::auth::check_present(const event &event) try { using json::at; @@ -170,7 +242,28 @@ try at<"room_id"_>(event) }; - const m::event::prev refs{event}; + return check(event, room); +} +catch(const std::exception &) +{ + return + { + false, std::current_exception() + }; +} + +ircd::m::room::auth::passfail +IRCD_MODULE_EXPORT +ircd::m::room::auth::check_static(const event &event) +try +{ + using json::at; + + const m::event::prev refs + { + event + }; + const auto count { refs.auth_events_count() @@ -184,14 +277,33 @@ try count, }; - // Vector of contingent event idxs from the event and the present state - m::event::idx idxs[9] + m::event::idx idx[4] { count > 0? m::index(refs.auth_event(0)): 0UL, count > 1? m::index(refs.auth_event(1)): 0UL, count > 2? m::index(refs.auth_event(2)): 0UL, count > 3? m::index(refs.auth_event(3)): 0UL, + }; + return check(event, vector_view{idx, count}); +} +catch(const std::exception &) +{ + return + { + false, std::current_exception() + }; +} + +ircd::m::room::auth::passfail +IRCD_MODULE_EXPORT +ircd::m::room::auth::check(const event &event, + const room &room) +{ + using json::at; + + m::event::idx idx[5] + { room.get(std::nothrow, "m.room.create", ""), room.get(std::nothrow, "m.room.power_levels", ""), room.get(std::nothrow, "m.room.member", at<"sender"_>(event)), @@ -205,58 +317,36 @@ try room.get(std::nothrow, "m.room.member", at<"state_key"_>(event)): 0UL, }; - m::event::fetch auth[9]; - for(size_t i(0); i < 9; ++i) - if(idxs[i]) - seek(auth[i], idxs[i], std::nothrow); - - size_t i, j; - const m::event *authv[4]; - for(i = 0, j = 0; i < 4 && j < 4; ++i) - if(auth[i].valid) - authv[j++] = &auth[i]; - - hookdata data - { - event, {authv, j} - }; - - auto ret - { - check(std::nothrow, event, data) - }; - - if(!std::get(ret) || std::get(ret)) - return ret; - - for(i = 4, j = 0; i < 9 && j < 4; ++i) - if(auth[i].valid) - authv[j++] = &auth[i]; - - data = - { - event, {authv, j} - }; - - ret = - { - check(std::nothrow, event, data) - }; - - return ret; -} -catch(const std::exception &) -{ - return - { - false, std::current_exception() - }; + return check(event, vector_view{idx, 5}); } ircd::m::room::auth::passfail IRCD_MODULE_EXPORT -ircd::m::room::auth::check(std::nothrow_t, - const event &event, +ircd::m::room::auth::check(const event &event, + const vector_view &idx) +{ + std::array auth; + for(size_t i(0), j(0); i < idx.size(); ++i) + if(idx.at(i)) + m::seek(auth.at(j++), idx.at(i), std::nothrow); + + size_t j(0); + std::array authv; + for(size_t i(0); i < auth.size(); ++i) + if(auth.at(i).valid) + authv.at(j++) = &auth.at(i); + + hookdata data + { + event, {authv.data(), j} + }; + + return check(event, data); +} + +ircd::m::room::auth::passfail +IRCD_MODULE_EXPORT +ircd::m::room::auth::check(const event &event, hookdata &data) try {