mirror of
https://github.com/matrix-construct/construct
synced 2025-02-26 13:40:20 +01:00
ircd:Ⓜ️ Move event::auth to room::auth; move to module.
This commit is contained in:
parent
e3ced849ee
commit
59618c6a44
26 changed files with 945 additions and 944 deletions
|
@ -1,94 +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.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#define HAVE_IRCD_M_EVENT_AUTH_H
|
|
||||||
|
|
||||||
struct ircd::m::event::auth
|
|
||||||
{
|
|
||||||
struct hookdata;
|
|
||||||
struct refs;
|
|
||||||
struct chain;
|
|
||||||
using passfail = std::tuple<bool, std::exception_ptr>;
|
|
||||||
using events_view = vector_view<const event *>;
|
|
||||||
IRCD_M_EXCEPTION(error, FAIL, http::UNAUTHORIZED)
|
|
||||||
|
|
||||||
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 void check(const event &);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Interface to the references made by other power events to this power
|
|
||||||
/// event in the `auth_events`. This interface only deals with power events,
|
|
||||||
/// it doesn't care if a non-power event referenced a power event. This does
|
|
||||||
/// not contain the auth-chain or state resolution algorithm here, those are
|
|
||||||
/// later constructed out of this data.
|
|
||||||
struct ircd::m::event::auth::refs
|
|
||||||
{
|
|
||||||
event::idx idx;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using closure_bool = event::closure_idx_bool;
|
|
||||||
|
|
||||||
bool for_each(const string_view &type, const closure_bool &) const;
|
|
||||||
bool for_each(const closure_bool &) const;
|
|
||||||
|
|
||||||
bool has(const string_view &type) const noexcept;
|
|
||||||
bool has(const event::idx &) const noexcept;
|
|
||||||
|
|
||||||
size_t count(const string_view &type) const noexcept;
|
|
||||||
size_t count() const noexcept;
|
|
||||||
|
|
||||||
refs(const event::idx &idx)
|
|
||||||
:idx{idx}
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ircd::m::event::auth::chain
|
|
||||||
{
|
|
||||||
using closure_bool = event::closure_idx_bool;
|
|
||||||
using closure = event::closure_idx;
|
|
||||||
|
|
||||||
event::idx idx;
|
|
||||||
|
|
||||||
static bool for_each(const auth::chain &, const closure_bool &);
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool for_each(const closure_bool &) const;
|
|
||||||
bool for_each(const closure &) const;
|
|
||||||
|
|
||||||
bool has(const string_view &type) const noexcept;
|
|
||||||
size_t depth() const noexcept;
|
|
||||||
|
|
||||||
chain(const event::idx &idx)
|
|
||||||
:idx{idx}
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ircd::m::event::auth::hookdata
|
|
||||||
{
|
|
||||||
const event *find(const event::closure_bool &) const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
event::prev prev;
|
|
||||||
vector_view<const event *> auth_events;
|
|
||||||
const event *auth_create {nullptr};
|
|
||||||
const event *auth_power {nullptr};
|
|
||||||
const event *auth_join_rules {nullptr};
|
|
||||||
const event *auth_member_target {nullptr};
|
|
||||||
const event *auth_member_sender {nullptr};
|
|
||||||
|
|
||||||
bool allow {false};
|
|
||||||
std::exception_ptr fail;
|
|
||||||
|
|
||||||
hookdata(const event &, const events_view &auth_events);
|
|
||||||
};
|
|
|
@ -98,7 +98,6 @@ struct ircd::m::event
|
||||||
struct prev;
|
struct prev;
|
||||||
struct refs;
|
struct refs;
|
||||||
struct horizon;
|
struct horizon;
|
||||||
struct auth;
|
|
||||||
struct fetch;
|
struct fetch;
|
||||||
struct conforms;
|
struct conforms;
|
||||||
struct append;
|
struct append;
|
||||||
|
@ -162,7 +161,6 @@ struct ircd::m::event
|
||||||
#include "prev.h"
|
#include "prev.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "horizon.h"
|
#include "horizon.h"
|
||||||
#include "auth.h"
|
|
||||||
#include "index.h"
|
#include "index.h"
|
||||||
#include "event_id.h"
|
#include "event_id.h"
|
||||||
#include "fetch.h"
|
#include "fetch.h"
|
||||||
|
|
|
@ -15,17 +15,87 @@
|
||||||
///
|
///
|
||||||
struct ircd::m::room::auth
|
struct ircd::m::room::auth
|
||||||
{
|
{
|
||||||
using closure_bool = std::function<bool (const event::idx &)>;
|
struct refs;
|
||||||
using closure = std::function<void (const event::idx &)>;
|
struct chain;
|
||||||
|
struct hookdata;
|
||||||
using types = vector_view<const string_view>;
|
using types = vector_view<const string_view>;
|
||||||
|
using events_view = vector_view<const event *>;
|
||||||
|
using passfail = std::tuple<bool, std::exception_ptr>;
|
||||||
|
IRCD_M_EXCEPTION(error, FAIL, http::UNAUTHORIZED)
|
||||||
|
|
||||||
m::room room;
|
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 void check(const event &);
|
||||||
|
|
||||||
|
static bool generate(json::stack::array &, const m::room &, const m::event &);
|
||||||
|
static json::array generate(const mutable_buffer &, const m::room &, const m::event &);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Interface to the references made by other power events to this power
|
||||||
|
/// event in the `auth_events`. This interface only deals with power events,
|
||||||
|
/// it doesn't care if a non-power event referenced a power event. This does
|
||||||
|
/// not contain the auth-chain or state resolution algorithm here, those are
|
||||||
|
/// later constructed out of this data.
|
||||||
|
struct ircd::m::room::auth::refs
|
||||||
|
{
|
||||||
|
event::idx idx;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool make_refs(json::stack::array &, const m::event &) const;
|
using closure_bool = event::closure_idx_bool;
|
||||||
json::array make_refs(const mutable_buffer &, const m::event &) const;
|
|
||||||
|
|
||||||
auth(const m::room &room)
|
bool for_each(const string_view &type, const closure_bool &) const;
|
||||||
:room{room}
|
bool for_each(const closure_bool &) const;
|
||||||
|
|
||||||
|
bool has(const string_view &type) const noexcept;
|
||||||
|
bool has(const event::idx &) const noexcept;
|
||||||
|
|
||||||
|
size_t count(const string_view &type) const noexcept;
|
||||||
|
size_t count() const noexcept;
|
||||||
|
|
||||||
|
refs(const event::idx &idx)
|
||||||
|
:idx{idx}
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ircd::m::room::auth::chain
|
||||||
|
{
|
||||||
|
using closure_bool = event::closure_idx_bool;
|
||||||
|
using closure = event::closure_idx;
|
||||||
|
|
||||||
|
event::idx idx;
|
||||||
|
|
||||||
|
static bool for_each(const auth::chain &, const closure_bool &);
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool for_each(const closure_bool &) const;
|
||||||
|
bool for_each(const closure &) const;
|
||||||
|
|
||||||
|
bool has(const string_view &type) const noexcept;
|
||||||
|
size_t depth() const noexcept;
|
||||||
|
|
||||||
|
chain(const event::idx &idx)
|
||||||
|
:idx{idx}
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ircd::m::room::auth::hookdata
|
||||||
|
{
|
||||||
|
const event *find(const event::closure_bool &) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
event::prev prev;
|
||||||
|
vector_view<const event *> auth_events;
|
||||||
|
const event *auth_create {nullptr};
|
||||||
|
const event *auth_power {nullptr};
|
||||||
|
const event *auth_join_rules {nullptr};
|
||||||
|
const event *auth_member_target {nullptr};
|
||||||
|
const event *auth_member_sender {nullptr};
|
||||||
|
|
||||||
|
bool allow {false};
|
||||||
|
std::exception_ptr fail;
|
||||||
|
|
||||||
|
hookdata(const event &, const events_view &auth_events);
|
||||||
|
hookdata() = default;
|
||||||
|
};
|
||||||
|
|
|
@ -210,6 +210,8 @@ ircd::m::module_names
|
||||||
"m_user_events",
|
"m_user_events",
|
||||||
"m_user_highlight",
|
"m_user_highlight",
|
||||||
"m_user_profile",
|
"m_user_profile",
|
||||||
|
"m_room",
|
||||||
|
"m_room_auth",
|
||||||
"m_room_timeline",
|
"m_room_timeline",
|
||||||
"m_room_aliases",
|
"m_room_aliases",
|
||||||
"m_room_canonical_alias",
|
"m_room_canonical_alias",
|
||||||
|
|
|
@ -581,7 +581,14 @@ ircd::m::dbs::_index_event_refs_auth(db::txn &txn,
|
||||||
{
|
{
|
||||||
assert(opts.appendix.test(appendix::EVENT_REFS));
|
assert(opts.appendix.test(appendix::EVENT_REFS));
|
||||||
assert(opts.event_refs.test(uint(ref::NEXT_AUTH)));
|
assert(opts.event_refs.test(uint(ref::NEXT_AUTH)));
|
||||||
if(!event::auth::is_power_event(event))
|
|
||||||
|
//TODO: XXX module dep
|
||||||
|
static mods::import<bool (const m::event &)> is_power_event
|
||||||
|
{
|
||||||
|
"m_room_auth", "ircd::m::room::auth::is_power_event"
|
||||||
|
};
|
||||||
|
|
||||||
|
if(!is_power_event(event))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const event::prev prev{event};
|
const event::prev prev{event};
|
||||||
|
|
631
ircd/m_event.cc
631
ircd/m_event.cc
|
@ -1652,637 +1652,6 @@ ircd::m::index(const event::id &event_id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// event/auth.h
|
|
||||||
//
|
|
||||||
|
|
||||||
namespace ircd::m
|
|
||||||
{
|
|
||||||
static void check_event_auth_rule_9(const m::event &, event::auth::hookdata &);
|
|
||||||
static void check_event_auth_rule_8(const m::event &, event::auth::hookdata &);
|
|
||||||
static void check_event_auth_rule_6(const m::event &, event::auth::hookdata &);
|
|
||||||
static void check_event_auth_rule_3(const m::event &, event::auth::hookdata &);
|
|
||||||
static void check_event_auth_rule_2(const m::event &, event::auth::hookdata &);
|
|
||||||
|
|
||||||
extern hook::site<event::auth::hookdata &> event_auth_hook;
|
|
||||||
}
|
|
||||||
|
|
||||||
decltype(ircd::m::event_auth_hook)
|
|
||||||
ircd::m::event_auth_hook
|
|
||||||
{
|
|
||||||
{ "name", "event.auth" },
|
|
||||||
{ "exceptions", true },
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// event::auth
|
|
||||||
//
|
|
||||||
|
|
||||||
void
|
|
||||||
ircd::m::event::auth::check(const event &event)
|
|
||||||
{
|
|
||||||
const auto &[pass, fail]
|
|
||||||
{
|
|
||||||
check(std::nothrow, event)
|
|
||||||
};
|
|
||||||
|
|
||||||
if(!pass)
|
|
||||||
{
|
|
||||||
assert(bool(fail));
|
|
||||||
std::rethrow_exception(fail);
|
|
||||||
__builtin_unreachable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ircd::m::event::auth::passfail
|
|
||||||
ircd::m::event::auth::check(std::nothrow_t,
|
|
||||||
const event &event)
|
|
||||||
{
|
|
||||||
using json::at;
|
|
||||||
|
|
||||||
const m::room room
|
|
||||||
{
|
|
||||||
at<"room_id"_>(event)
|
|
||||||
};
|
|
||||||
|
|
||||||
const m::event::prev refs{event};
|
|
||||||
const auto count
|
|
||||||
{
|
|
||||||
refs.auth_events_count()
|
|
||||||
};
|
|
||||||
|
|
||||||
if(count > 4)
|
|
||||||
log::dwarning
|
|
||||||
{
|
|
||||||
"Event %s has an unexpected %zu auth_events references",
|
|
||||||
string_view{event.event_id},
|
|
||||||
count,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Vector of contingent event idxs from the event and the present state
|
|
||||||
m::event::idx idxs[9]
|
|
||||||
{
|
|
||||||
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,
|
|
||||||
|
|
||||||
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)),
|
|
||||||
|
|
||||||
at<"type"_>(event) == "m.room.member" &&
|
|
||||||
(membership(event) == "join" || membership(event) == "invite")?
|
|
||||||
room.get(std::nothrow, "m.room.join_rules", ""): 0UL,
|
|
||||||
|
|
||||||
at<"type"_>(event) == "m.room.member" &&
|
|
||||||
at<"sender"_>(event) != at<"state_key"_>(event)?
|
|
||||||
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<bool>(ret) || std::get<std::exception_ptr>(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
ircd::m::event::auth::passfail
|
|
||||||
ircd::m::event::auth::check(std::nothrow_t,
|
|
||||||
const event &event,
|
|
||||||
hookdata &data)
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 1. If type is m.room.create:
|
|
||||||
if(json::get<"type"_>(event) == "m.room.create")
|
|
||||||
{
|
|
||||||
event_auth_hook(event, data);
|
|
||||||
return {data.allow, data.fail};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Reject if event has auth_events that:
|
|
||||||
check_event_auth_rule_2(event, data);
|
|
||||||
|
|
||||||
// 3. If event does not have a m.room.create in its auth_events, reject.
|
|
||||||
check_event_auth_rule_3(event, data);
|
|
||||||
|
|
||||||
// 4. If type is m.room.aliases
|
|
||||||
if(json::get<"type"_>(event) == "m.room.aliases")
|
|
||||||
{
|
|
||||||
event_auth_hook(event, data);
|
|
||||||
return {data.allow, data.fail};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. If type is m.room.member
|
|
||||||
if(json::get<"type"_>(event) == "m.room.member")
|
|
||||||
{
|
|
||||||
event_auth_hook(event, data);
|
|
||||||
return {data.allow, data.fail};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. If the sender's current membership state is not join, reject.
|
|
||||||
check_event_auth_rule_6(event, data);
|
|
||||||
|
|
||||||
// 7. If type is m.room.third_party_invite:
|
|
||||||
if(json::get<"type"_>(event) == "m.room.third_party_invite")
|
|
||||||
{
|
|
||||||
event_auth_hook(event, data);
|
|
||||||
return {data.allow, data.fail};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 8. If the event type's required power level is greater than the
|
|
||||||
// sender's power level, reject.
|
|
||||||
check_event_auth_rule_8(event, data);
|
|
||||||
|
|
||||||
// 9. If the event has a state_key that starts with an @ and does not
|
|
||||||
// match the sender, reject.
|
|
||||||
check_event_auth_rule_9(event, data);
|
|
||||||
|
|
||||||
// 10. If type is m.room.power_levels:
|
|
||||||
if(json::get<"type"_>(event) == "m.room.power_levels")
|
|
||||||
{
|
|
||||||
event_auth_hook(event, data);
|
|
||||||
return {data.allow, data.fail};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 11. If type is m.room.redaction:
|
|
||||||
if(json::get<"type"_>(event) == "m.room.redaction")
|
|
||||||
{
|
|
||||||
event_auth_hook(event, data);
|
|
||||||
return {data.allow, data.fail};
|
|
||||||
}
|
|
||||||
|
|
||||||
// (non-spec) Call the hook for any types without a branch enumerated
|
|
||||||
// here. The handler will throw on a failure, otherwise fallthrough to
|
|
||||||
// the next rule.
|
|
||||||
event_auth_hook(event, data);
|
|
||||||
|
|
||||||
// 12. Otherwise, allow.
|
|
||||||
data.allow = true;
|
|
||||||
assert(!data.fail);
|
|
||||||
return {data.allow, data.fail};
|
|
||||||
}
|
|
||||||
catch(const FAIL &e)
|
|
||||||
{
|
|
||||||
data.allow = false;
|
|
||||||
data.fail = std::current_exception();
|
|
||||||
return {data.allow, data.fail};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ircd::m::event::auth::is_power_event(const m::event &event)
|
|
||||||
{
|
|
||||||
if(!json::get<"type"_>(event))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(json::get<"type"_>(event) == "m.room.create")
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if(json::get<"type"_>(event) == "m.room.power_levels")
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if(json::get<"type"_>(event) == "m.room.join_rules")
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if(json::get<"type"_>(event) != "m.room.member")
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(!json::get<"sender"_>(event) || !json::get<"state_key"_>(event))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(json::get<"sender"_>(event) == json::get<"state_key"_>(event))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(membership(event) == "leave" || membership(event) == "ban")
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// m::event::auth internal
|
|
||||||
//
|
|
||||||
|
|
||||||
void
|
|
||||||
ircd::m::check_event_auth_rule_2(const m::event &event,
|
|
||||||
event::auth::hookdata &data)
|
|
||||||
{
|
|
||||||
using FAIL = event::auth::FAIL;
|
|
||||||
|
|
||||||
// 2. Reject if event has auth_events that:
|
|
||||||
for(size_t i(0); i < data.auth_events.size(); ++i)
|
|
||||||
{
|
|
||||||
// a. have duplicate entries for a given type and state_key pair
|
|
||||||
const m::event &a
|
|
||||||
{
|
|
||||||
*data.auth_events.at(i)
|
|
||||||
};
|
|
||||||
|
|
||||||
for(size_t j(0); j < data.auth_events.size(); ++j) if(i != j)
|
|
||||||
{
|
|
||||||
const m::event &b
|
|
||||||
{
|
|
||||||
*data.auth_events.at(j)
|
|
||||||
};
|
|
||||||
|
|
||||||
if(json::get<"type"_>(a) == json::get<"type"_>(b))
|
|
||||||
if(json::get<"state_key"_>(a) == json::get<"state_key"_>(b))
|
|
||||||
throw FAIL
|
|
||||||
{
|
|
||||||
"Duplicate (type,state_key) in auth_events."
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// b. have entries whose type and state_key don't match those specified by
|
|
||||||
// the auth events selection algorithm described in the server...
|
|
||||||
const string_view &type
|
|
||||||
{
|
|
||||||
json::get<"type"_>(a)
|
|
||||||
};
|
|
||||||
|
|
||||||
if(type == "m.room.create")
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(type == "m.room.power_levels")
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(type == "m.room.join_rules")
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(type == "m.room.member")
|
|
||||||
{
|
|
||||||
if(json::get<"sender"_>(event) == json::get<"state_key"_>(a))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(json::get<"state_key"_>(event) == json::get<"state_key"_>(a))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw FAIL
|
|
||||||
{
|
|
||||||
"Reference in auth_events is not an auth_event."
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ircd::m::check_event_auth_rule_3(const m::event &event,
|
|
||||||
event::auth::hookdata &data)
|
|
||||||
{
|
|
||||||
using FAIL = event::auth::FAIL;
|
|
||||||
|
|
||||||
// 3. If event does not have a m.room.create in its auth_events, reject.
|
|
||||||
if(!data.auth_create)
|
|
||||||
throw FAIL
|
|
||||||
{
|
|
||||||
"Missing m.room.create in auth_events."
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ircd::m::check_event_auth_rule_6(const m::event &event,
|
|
||||||
event::auth::hookdata &data)
|
|
||||||
{
|
|
||||||
using FAIL = event::auth::FAIL;
|
|
||||||
|
|
||||||
// 6. If the sender's current membership state is not join, reject.
|
|
||||||
if(data.auth_member_sender)
|
|
||||||
if(membership(*data.auth_member_sender) != "join")
|
|
||||||
throw FAIL
|
|
||||||
{
|
|
||||||
"sender is not joined to room."
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ircd::m::check_event_auth_rule_8(const m::event &event,
|
|
||||||
event::auth::hookdata &data)
|
|
||||||
{
|
|
||||||
using FAIL = event::auth::FAIL;
|
|
||||||
|
|
||||||
const m::room::power power
|
|
||||||
{
|
|
||||||
data.auth_power? *data.auth_power : m::event{}, *data.auth_create
|
|
||||||
};
|
|
||||||
|
|
||||||
// 8. If the event type's required power level is greater than the
|
|
||||||
// sender's power level, reject.
|
|
||||||
if(!power(at<"sender"_>(event), "events", at<"type"_>(event), json::get<"state_key"_>(event)))
|
|
||||||
throw FAIL
|
|
||||||
{
|
|
||||||
"sender has insufficient power for event type."
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ircd::m::check_event_auth_rule_9(const m::event &event,
|
|
||||||
event::auth::hookdata &data)
|
|
||||||
{
|
|
||||||
using FAIL = event::auth::FAIL;
|
|
||||||
|
|
||||||
// 9. If the event has a state_key that starts with an @ and does not
|
|
||||||
// match the sender, reject.
|
|
||||||
if(startswith(json::get<"state_key"_>(event), '@'))
|
|
||||||
if(at<"state_key"_>(event) != at<"sender"_>(event))
|
|
||||||
throw FAIL
|
|
||||||
{
|
|
||||||
"sender cannot set another user's mxid in a state_key."
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// event::auth::hookdata
|
|
||||||
//
|
|
||||||
|
|
||||||
ircd::m::event::auth::hookdata::hookdata(const m::event &event,
|
|
||||||
const vector_view<const m::event *> &auth_events)
|
|
||||||
:prev
|
|
||||||
{
|
|
||||||
event
|
|
||||||
}
|
|
||||||
,auth_events
|
|
||||||
{
|
|
||||||
auth_events
|
|
||||||
}
|
|
||||||
,auth_create
|
|
||||||
{
|
|
||||||
find([](const auto &event)
|
|
||||||
{
|
|
||||||
return json::get<"type"_>(event) == "m.room.create";
|
|
||||||
})
|
|
||||||
}
|
|
||||||
,auth_power
|
|
||||||
{
|
|
||||||
find([](const auto &event)
|
|
||||||
{
|
|
||||||
return json::get<"type"_>(event) == "m.room.power_levels";
|
|
||||||
})
|
|
||||||
}
|
|
||||||
,auth_join_rules
|
|
||||||
{
|
|
||||||
find([](const auto &event)
|
|
||||||
{
|
|
||||||
return json::get<"type"_>(event) == "m.room.join_rules";
|
|
||||||
})
|
|
||||||
}
|
|
||||||
,auth_member_target
|
|
||||||
{
|
|
||||||
find([&event](const auto &auth_event)
|
|
||||||
{
|
|
||||||
return json::get<"type"_>(auth_event) == "m.room.member" &&
|
|
||||||
json::get<"state_key"_>(auth_event) == json::get<"state_key"_>(event);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
,auth_member_sender
|
|
||||||
{
|
|
||||||
find([&event](const auto &auth_event)
|
|
||||||
{
|
|
||||||
return json::get<"type"_>(auth_event) == "m.room.member" &&
|
|
||||||
json::get<"state_key"_>(auth_event) == json::get<"sender"_>(event);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const ircd::m::event *
|
|
||||||
ircd::m::event::auth::hookdata::find(const event::closure_bool &closure)
|
|
||||||
const
|
|
||||||
{
|
|
||||||
for(const auto *const &event : auth_events)
|
|
||||||
if(likely(event) && closure(*event))
|
|
||||||
return event;
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// event::auth::refs
|
|
||||||
//
|
|
||||||
|
|
||||||
size_t
|
|
||||||
ircd::m::event::auth::refs::count()
|
|
||||||
const noexcept
|
|
||||||
{
|
|
||||||
return count(string_view{});
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
ircd::m::event::auth::refs::count(const string_view &type)
|
|
||||||
const noexcept
|
|
||||||
{
|
|
||||||
size_t ret(0);
|
|
||||||
for_each(type, [&ret](const auto &)
|
|
||||||
{
|
|
||||||
++ret;
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ircd::m::event::auth::refs::has(const event::idx &idx)
|
|
||||||
const noexcept
|
|
||||||
{
|
|
||||||
return !for_each([&idx](const event::idx &ref)
|
|
||||||
{
|
|
||||||
return ref != idx; // true to continue, false to break
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ircd::m::event::auth::refs::has(const string_view &type)
|
|
||||||
const noexcept
|
|
||||||
{
|
|
||||||
bool ret{false};
|
|
||||||
for_each(type, [&ret](const auto &)
|
|
||||||
{
|
|
||||||
ret = true;
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ircd::m::event::auth::refs::for_each(const closure_bool &closure)
|
|
||||||
const
|
|
||||||
{
|
|
||||||
return for_each(string_view{}, closure);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ircd::m::event::auth::refs::for_each(const string_view &type,
|
|
||||||
const closure_bool &closure)
|
|
||||||
const
|
|
||||||
{
|
|
||||||
assert(idx);
|
|
||||||
const event::refs erefs
|
|
||||||
{
|
|
||||||
idx
|
|
||||||
};
|
|
||||||
|
|
||||||
return erefs.for_each(dbs::ref::NEXT_AUTH, [this, &type, &closure]
|
|
||||||
(const event::idx &ref, const dbs::ref &)
|
|
||||||
{
|
|
||||||
bool match;
|
|
||||||
const auto matcher
|
|
||||||
{
|
|
||||||
[&type, &match](const string_view &type_)
|
|
||||||
{
|
|
||||||
match = type == type_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if(type)
|
|
||||||
{
|
|
||||||
if(!m::get(std::nothrow, ref, "type", matcher))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if(!match)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(idx != ref);
|
|
||||||
if(!closure(ref))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// event::auth::chain
|
|
||||||
//
|
|
||||||
|
|
||||||
size_t
|
|
||||||
ircd::m::event::auth::chain::depth()
|
|
||||||
const noexcept
|
|
||||||
{
|
|
||||||
size_t ret(0);
|
|
||||||
for_each([&ret](const auto &)
|
|
||||||
{
|
|
||||||
++ret;
|
|
||||||
});
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ircd::m::event::auth::chain::has(const string_view &type)
|
|
||||||
const noexcept
|
|
||||||
{
|
|
||||||
bool ret(false);
|
|
||||||
for_each(closure_bool{[&type, &ret]
|
|
||||||
(const auto &idx)
|
|
||||||
{
|
|
||||||
m::get(std::nothrow, idx, "type", [&type, &ret]
|
|
||||||
(const auto &value)
|
|
||||||
{
|
|
||||||
ret = value == type;
|
|
||||||
});
|
|
||||||
|
|
||||||
return !ret;
|
|
||||||
}});
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ircd::m::event::auth::chain::for_each(const closure &closure)
|
|
||||||
const
|
|
||||||
{
|
|
||||||
return for_each(closure_bool{[&closure]
|
|
||||||
(const auto &idx)
|
|
||||||
{
|
|
||||||
closure(idx);
|
|
||||||
return true;
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ircd::m::event::auth::chain::for_each(const closure_bool &closure)
|
|
||||||
const
|
|
||||||
{
|
|
||||||
return chain::for_each(*this, closure);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ircd::m::event::auth::chain::for_each(const auth::chain &c,
|
|
||||||
const closure_bool &closure)
|
|
||||||
{
|
|
||||||
m::event::fetch e, a;
|
|
||||||
std::set<event::idx> ae;
|
|
||||||
std::deque<event::idx> aq {c.idx}; do
|
|
||||||
{
|
|
||||||
const auto idx(aq.front());
|
|
||||||
aq.pop_front();
|
|
||||||
if(!seek(e, idx, std::nothrow))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const m::event::prev prev{e};
|
|
||||||
const auto count(prev.auth_events_count());
|
|
||||||
for(size_t i(0); i < count && i < 4; ++i)
|
|
||||||
{
|
|
||||||
const auto &auth_event_id(prev.auth_event(i));
|
|
||||||
const auto &auth_event_idx(index(auth_event_id, std::nothrow));
|
|
||||||
if(!auth_event_idx)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto it(ae.lower_bound(auth_event_idx));
|
|
||||||
if(it == end(ae) || *it != auth_event_idx)
|
|
||||||
{
|
|
||||||
seek(a, auth_event_idx, std::nothrow);
|
|
||||||
ae.emplace_hint(it, auth_event_idx);
|
|
||||||
if(a.valid)
|
|
||||||
aq.emplace_back(auth_event_idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while(!aq.empty());
|
|
||||||
|
|
||||||
for(const auto &idx : ae)
|
|
||||||
if(!closure(idx))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// event/horizon.h
|
// event/horizon.h
|
||||||
|
|
102
ircd/m_room.cc
102
ircd/m_room.cc
|
@ -3703,108 +3703,6 @@ ircd::m::room::head::for_each(const head &head,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// room::auth
|
|
||||||
//
|
|
||||||
|
|
||||||
ircd::json::array
|
|
||||||
ircd::m::room::auth::make_refs(const mutable_buffer &buf,
|
|
||||||
const m::event &event)
|
|
||||||
const
|
|
||||||
{
|
|
||||||
json::stack out{buf};
|
|
||||||
json::stack::checkpoint cp{out};
|
|
||||||
{
|
|
||||||
json::stack::array array{out};
|
|
||||||
if(!make_refs(array, event))
|
|
||||||
cp.decommit();
|
|
||||||
}
|
|
||||||
|
|
||||||
return json::array{out.completed()};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ircd::m::room::auth::make_refs(json::stack::array &out,
|
|
||||||
const m::event &event)
|
|
||||||
const
|
|
||||||
{
|
|
||||||
const m::event::id::closure &v1_ref{[&out]
|
|
||||||
(const auto &event_id)
|
|
||||||
{
|
|
||||||
json::stack::array auth{out};
|
|
||||||
auth.append(event_id);
|
|
||||||
{
|
|
||||||
json::stack::object nilly{auth};
|
|
||||||
json::stack::member willy
|
|
||||||
{
|
|
||||||
nilly, "", ""
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
|
|
||||||
const m::event::id::closure &v3_ref{[&out]
|
|
||||||
(const auto &event_id)
|
|
||||||
{
|
|
||||||
out.append(event_id);
|
|
||||||
}};
|
|
||||||
|
|
||||||
char versionbuf[64];
|
|
||||||
const auto version
|
|
||||||
{
|
|
||||||
m::version(versionbuf, room, std::nothrow)
|
|
||||||
};
|
|
||||||
|
|
||||||
assert(version);
|
|
||||||
const auto &fetch_append
|
|
||||||
{
|
|
||||||
version == "1" || version == "2"? v1_ref : v3_ref
|
|
||||||
};
|
|
||||||
|
|
||||||
const m::room::state state
|
|
||||||
{
|
|
||||||
room
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto &type
|
|
||||||
{
|
|
||||||
json::get<"type"_>(event)
|
|
||||||
};
|
|
||||||
|
|
||||||
if(!type)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(type == "m.room.create")
|
|
||||||
return false;
|
|
||||||
|
|
||||||
state.get(std::nothrow, "m.room.create", "", fetch_append);
|
|
||||||
state.get(std::nothrow, "m.room.power_levels", "", fetch_append);
|
|
||||||
|
|
||||||
if(type == "m.room.member")
|
|
||||||
if(!m::membership(event) || m::membership(event) == "join")
|
|
||||||
state.get(std::nothrow, "m.room.join_rules", "", fetch_append);
|
|
||||||
|
|
||||||
const string_view member_sender
|
|
||||||
{
|
|
||||||
defined(json::get<"sender"_>(event))?
|
|
||||||
m::user::id{at<"sender"_>(event)}:
|
|
||||||
m::user::id{}
|
|
||||||
};
|
|
||||||
|
|
||||||
if(member_sender)
|
|
||||||
state.get(std::nothrow, "m.room.member", member_sender, fetch_append);
|
|
||||||
|
|
||||||
m::user::id member_target;
|
|
||||||
if(json::get<"sender"_>(event) && json::get<"state_key"_>(event))
|
|
||||||
if(at<"sender"_>(event) != at<"state_key"_>(event))
|
|
||||||
if(valid(m::id::USER, at<"state_key"_>(event)))
|
|
||||||
member_target = at<"state_key"_>(event);
|
|
||||||
|
|
||||||
if(member_target)
|
|
||||||
state.get(std::nothrow, "m.room.member", member_target, fetch_append);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// room::aliases
|
// room::aliases
|
||||||
//
|
//
|
||||||
|
|
|
@ -129,6 +129,7 @@ m_events_la_SOURCES = m_events.cc
|
||||||
m_rooms_la_SOURCES = m_rooms.cc
|
m_rooms_la_SOURCES = m_rooms.cc
|
||||||
m_rooms_summary_la_SOURCES = m_rooms_summary.cc
|
m_rooms_summary_la_SOURCES = m_rooms_summary.cc
|
||||||
m_room_la_SOURCES = m_room.cc
|
m_room_la_SOURCES = m_room.cc
|
||||||
|
m_room_auth_la_SOURCES = m_room_auth.cc
|
||||||
m_room_timeline_la_SOURCES = m_room_timeline.cc
|
m_room_timeline_la_SOURCES = m_room_timeline.cc
|
||||||
m_room_create_la_SOURCES = m_room_create.cc
|
m_room_create_la_SOURCES = m_room_create.cc
|
||||||
m_room_member_la_SOURCES = m_room_member.cc
|
m_room_member_la_SOURCES = m_room_member.cc
|
||||||
|
@ -179,6 +180,7 @@ m_module_LTLIBRARIES = \
|
||||||
m_rooms.la \
|
m_rooms.la \
|
||||||
m_rooms_summary.la \
|
m_rooms_summary.la \
|
||||||
m_room.la \
|
m_room.la \
|
||||||
|
m_room_auth.la \
|
||||||
m_room_timeline.la \
|
m_room_timeline.la \
|
||||||
m_room_create.la \
|
m_room_create.la \
|
||||||
m_room_member.la \
|
m_room_member.la \
|
||||||
|
|
|
@ -5921,13 +5921,11 @@ console_cmd__stage__make_auth(opt &out, const string_view &line)
|
||||||
at<"room_id"_>(event)
|
at<"room_id"_>(event)
|
||||||
};
|
};
|
||||||
|
|
||||||
const m::room::auth auth
|
|
||||||
{
|
|
||||||
room
|
|
||||||
};
|
|
||||||
|
|
||||||
thread_local char buf[1024];
|
thread_local char buf[1024];
|
||||||
json::get<"auth_events"_>(event) = auth.make_refs(buf, event);
|
json::get<"auth_events"_>(event) =
|
||||||
|
{
|
||||||
|
m::room::auth::generate(buf, room, event)
|
||||||
|
};
|
||||||
|
|
||||||
stage.at(id) = json::strung
|
stage.at(id) = json::strung
|
||||||
{
|
{
|
||||||
|
@ -6653,7 +6651,7 @@ console_cmd__event(opt &out, const string_view &line)
|
||||||
out << std::endl;
|
out << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m::event::auth::is_power_event(event))
|
if(m::room::auth::is_power_event(event))
|
||||||
out << std::setw(16) << std::right << "POWER EVENT" << " "
|
out << std::setw(16) << std::right << "POWER EVENT" << " "
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
|
@ -6743,7 +6741,7 @@ console_cmd__event(opt &out, const string_view &line)
|
||||||
<< "HASH MISMATCH :" << b64encode_unpadded(hash(event))
|
<< "HASH MISMATCH :" << b64encode_unpadded(hash(event))
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
const auto &[authed, failmsg](m::event::auth::check(std::nothrow, event));
|
const auto &[authed, failmsg](m::room::auth::check(std::nothrow, event));
|
||||||
if(!authed)
|
if(!authed)
|
||||||
out << std::setw(9) << std::left << "!!! ERROR" << " "
|
out << std::setw(9) << std::left << "!!! ERROR" << " "
|
||||||
<< "UNAUTHORIZED :" << what(failmsg)
|
<< "UNAUTHORIZED :" << what(failmsg)
|
||||||
|
@ -7194,25 +7192,13 @@ console_cmd__event__auth(opt &out, const string_view &line)
|
||||||
param.at("event_id")
|
param.at("event_id")
|
||||||
};
|
};
|
||||||
|
|
||||||
const m::event::auth::chain ac
|
const m::event::fetch event
|
||||||
{
|
{
|
||||||
m::index(event_id)
|
event_id
|
||||||
};
|
};
|
||||||
|
|
||||||
ac.for_each([&out](const auto &idx)
|
m::room::auth::check(event);
|
||||||
{
|
out << "pass" << std::endl;
|
||||||
const m::event::fetch event
|
|
||||||
{
|
|
||||||
idx, std::nothrow
|
|
||||||
};
|
|
||||||
|
|
||||||
out << idx;
|
|
||||||
if(event.valid)
|
|
||||||
out << " " << pretty_oneline(event);
|
|
||||||
|
|
||||||
out << std::endl;
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7340,7 +7326,7 @@ console_cmd__event__refs__auth(opt &out, const string_view &line)
|
||||||
param.at("type", ""_sv)
|
param.at("type", ""_sv)
|
||||||
};
|
};
|
||||||
|
|
||||||
const m::event::auth::refs auth
|
const m::room::auth::refs auth
|
||||||
{
|
{
|
||||||
index(event_id)
|
index(event_id)
|
||||||
};
|
};
|
||||||
|
@ -9995,15 +9981,24 @@ console_cmd__room__auth(opt &out, const string_view &line)
|
||||||
p0
|
p0
|
||||||
};
|
};
|
||||||
|
|
||||||
const m::room room
|
const m::room::auth::chain ac
|
||||||
{
|
{
|
||||||
room_id, event_id
|
m::index(event_id)
|
||||||
};
|
};
|
||||||
|
|
||||||
const m::room::auth auth
|
ac.for_each([&out](const auto &idx)
|
||||||
{
|
{
|
||||||
room
|
const m::event::fetch event
|
||||||
};
|
{
|
||||||
|
idx, std::nothrow
|
||||||
|
};
|
||||||
|
|
||||||
|
out << idx;
|
||||||
|
if(event.valid)
|
||||||
|
out << " " << pretty_oneline(event);
|
||||||
|
|
||||||
|
out << std::endl;
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -12821,7 +12816,7 @@ console_cmd__fed__query_auth(opt &out, const string_view &line)
|
||||||
top, "auth_chain"
|
top, "auth_chain"
|
||||||
};
|
};
|
||||||
|
|
||||||
const m::event::auth::chain chain
|
const m::room::auth::chain chain
|
||||||
{
|
{
|
||||||
m::index(event_id)
|
m::index(event_id)
|
||||||
};
|
};
|
||||||
|
|
|
@ -113,7 +113,7 @@ get__event_auth(client &client,
|
||||||
top, "auth_chain"
|
top, "auth_chain"
|
||||||
};
|
};
|
||||||
|
|
||||||
const m::event::auth::chain chain
|
const m::room::auth::chain chain
|
||||||
{
|
{
|
||||||
m::index(event_id)
|
m::index(event_id)
|
||||||
};
|
};
|
||||||
|
|
|
@ -137,7 +137,6 @@ get__make_join(client &client,
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
const m::room::auth auth{room};
|
|
||||||
json::stack::checkpoint cp{out};
|
json::stack::checkpoint cp{out};
|
||||||
json::stack::array auth_events
|
json::stack::array auth_events
|
||||||
{
|
{
|
||||||
|
@ -151,7 +150,7 @@ get__make_join(client &client,
|
||||||
{ "sender", user_id },
|
{ "sender", user_id },
|
||||||
};
|
};
|
||||||
|
|
||||||
if(!auth.make_refs(auth_events, m::event{args}))
|
if(!m::room::auth::generate(auth_events, room, m::event{args}))
|
||||||
cp.decommit();
|
cp.decommit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,6 @@ get__make_leave(client &client,
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
const m::room::auth auth{room};
|
|
||||||
json::stack::checkpoint cp{out};
|
json::stack::checkpoint cp{out};
|
||||||
json::stack::array auth_events
|
json::stack::array auth_events
|
||||||
{
|
{
|
||||||
|
@ -122,7 +121,7 @@ get__make_leave(client &client,
|
||||||
}}
|
}}
|
||||||
};
|
};
|
||||||
|
|
||||||
if(!auth.make_refs(auth_events, m::event{args}))
|
if(!m::room::auth::generate(auth_events, room, m::event{args}))
|
||||||
cp.decommit();
|
cp.decommit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ put__send_join(client &client,
|
||||||
room_id
|
room_id
|
||||||
};
|
};
|
||||||
|
|
||||||
const m::event::auth::chain auth_chain
|
const m::room::auth::chain auth_chain
|
||||||
{
|
{
|
||||||
m::head_idx(room_id)
|
m::head_idx(room_id)
|
||||||
};
|
};
|
||||||
|
|
|
@ -74,7 +74,7 @@ get__state(client &client,
|
||||||
room
|
room
|
||||||
};
|
};
|
||||||
|
|
||||||
const m::event::auth::chain ac
|
const m::room::auth::chain ac
|
||||||
{
|
{
|
||||||
event_id?
|
event_id?
|
||||||
m::index(event_id):
|
m::index(event_id):
|
||||||
|
|
|
@ -67,7 +67,7 @@ get__state_ids(client &client,
|
||||||
room
|
room
|
||||||
};
|
};
|
||||||
|
|
||||||
const m::event::auth::chain ac
|
const m::room::auth::chain ac
|
||||||
{
|
{
|
||||||
event_id?
|
event_id?
|
||||||
m::index(event_id):
|
m::index(event_id):
|
||||||
|
|
|
@ -15,8 +15,8 @@ namespace ircd::m
|
||||||
extern const room::id::buf alias_room_id;
|
extern const room::id::buf alias_room_id;
|
||||||
extern const room alias_room;
|
extern const room alias_room;
|
||||||
|
|
||||||
static void auth_room_aliases(const event &, event::auth::hookdata &);
|
static void auth_room_aliases(const event &, room::auth::hookdata &);
|
||||||
extern hookfn<event::auth::hookdata &> auth_room_aliases_hookfn;
|
extern hookfn<room::auth::hookdata &> auth_room_aliases_hookfn;
|
||||||
|
|
||||||
static void changed_room_aliases(const event &, vm::eval &);
|
static void changed_room_aliases(const event &, vm::eval &);
|
||||||
extern hookfn<vm::eval &> changed_room_aliases_hookfn;
|
extern hookfn<vm::eval &> changed_room_aliases_hookfn;
|
||||||
|
@ -139,16 +139,16 @@ ircd::m::auth_room_aliases_hookfn
|
||||||
{
|
{
|
||||||
auth_room_aliases,
|
auth_room_aliases,
|
||||||
{
|
{
|
||||||
{ "_site", "event.auth" },
|
{ "_site", "room.auth" },
|
||||||
{ "type", "m.room.aliases" },
|
{ "type", "m.room.aliases" },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
ircd::m::auth_room_aliases(const event &event,
|
ircd::m::auth_room_aliases(const event &event,
|
||||||
event::auth::hookdata &data)
|
room::auth::hookdata &data)
|
||||||
{
|
{
|
||||||
using FAIL = m::event::auth::FAIL;
|
using FAIL = m::room::auth::FAIL;
|
||||||
using conforms = m::event::conforms;
|
using conforms = m::event::conforms;
|
||||||
|
|
||||||
// 4. If type is m.room.aliases:
|
// 4. If type is m.room.aliases:
|
||||||
|
|
761
modules/m_room_auth.cc
Normal file
761
modules/m_room_auth.cc
Normal file
|
@ -0,0 +1,761 @@
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
static void check_room_auth_rule_9(const m::event &, room::auth::hookdata &);
|
||||||
|
static void check_room_auth_rule_8(const m::event &, room::auth::hookdata &);
|
||||||
|
static void check_room_auth_rule_6(const m::event &, room::auth::hookdata &);
|
||||||
|
static void check_room_auth_rule_3(const m::event &, room::auth::hookdata &);
|
||||||
|
static void check_room_auth_rule_2(const m::event &, room::auth::hookdata &);
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
{ "name", "room.auth" },
|
||||||
|
{ "exceptions", true },
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// generate
|
||||||
|
//
|
||||||
|
|
||||||
|
ircd::json::array
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::generate(const mutable_buffer &buf,
|
||||||
|
const m::room &room,
|
||||||
|
const m::event &event)
|
||||||
|
{
|
||||||
|
json::stack out{buf};
|
||||||
|
json::stack::checkpoint cp{out};
|
||||||
|
{
|
||||||
|
json::stack::array array{out};
|
||||||
|
if(!generate(array, room, event))
|
||||||
|
cp.decommit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return json::array{out.completed()};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::generate(json::stack::array &out,
|
||||||
|
const m::room &room,
|
||||||
|
const m::event &event)
|
||||||
|
{
|
||||||
|
const m::event::id::closure &v1_ref{[&out]
|
||||||
|
(const auto &event_id)
|
||||||
|
{
|
||||||
|
json::stack::array auth{out};
|
||||||
|
auth.append(event_id);
|
||||||
|
{
|
||||||
|
json::stack::object nilly{auth};
|
||||||
|
json::stack::member willy
|
||||||
|
{
|
||||||
|
nilly, "", ""
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
|
||||||
|
const m::event::id::closure &v3_ref{[&out]
|
||||||
|
(const auto &event_id)
|
||||||
|
{
|
||||||
|
out.append(event_id);
|
||||||
|
}};
|
||||||
|
|
||||||
|
char versionbuf[64];
|
||||||
|
const auto version
|
||||||
|
{
|
||||||
|
m::version(versionbuf, room, std::nothrow)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(version);
|
||||||
|
const auto &fetch_append
|
||||||
|
{
|
||||||
|
version == "1" || version == "2"? v1_ref : v3_ref
|
||||||
|
};
|
||||||
|
|
||||||
|
const m::room::state state
|
||||||
|
{
|
||||||
|
room
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto &type
|
||||||
|
{
|
||||||
|
json::get<"type"_>(event)
|
||||||
|
};
|
||||||
|
|
||||||
|
if(!type)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(type == "m.room.create")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.get(std::nothrow, "m.room.create", "", fetch_append);
|
||||||
|
state.get(std::nothrow, "m.room.power_levels", "", fetch_append);
|
||||||
|
|
||||||
|
if(type == "m.room.member")
|
||||||
|
if(!m::membership(event) || m::membership(event) == "join")
|
||||||
|
state.get(std::nothrow, "m.room.join_rules", "", fetch_append);
|
||||||
|
|
||||||
|
const string_view member_sender
|
||||||
|
{
|
||||||
|
defined(json::get<"sender"_>(event))?
|
||||||
|
m::user::id{at<"sender"_>(event)}:
|
||||||
|
m::user::id{}
|
||||||
|
};
|
||||||
|
|
||||||
|
if(member_sender)
|
||||||
|
state.get(std::nothrow, "m.room.member", member_sender, fetch_append);
|
||||||
|
|
||||||
|
m::user::id member_target;
|
||||||
|
if(json::get<"sender"_>(event) && json::get<"state_key"_>(event))
|
||||||
|
if(at<"sender"_>(event) != at<"state_key"_>(event))
|
||||||
|
if(valid(m::id::USER, at<"state_key"_>(event)))
|
||||||
|
member_target = at<"state_key"_>(event);
|
||||||
|
|
||||||
|
if(member_target)
|
||||||
|
state.get(std::nothrow, "m.room.member", member_target, fetch_append);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// check
|
||||||
|
//
|
||||||
|
|
||||||
|
void
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::check(const event &event)
|
||||||
|
{
|
||||||
|
const auto &[pass, fail]
|
||||||
|
{
|
||||||
|
check(std::nothrow, event)
|
||||||
|
};
|
||||||
|
|
||||||
|
if(!pass)
|
||||||
|
{
|
||||||
|
assert(bool(fail));
|
||||||
|
std::rethrow_exception(fail);
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ircd::m::room::auth::passfail
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::check(std::nothrow_t,
|
||||||
|
const event &event)
|
||||||
|
{
|
||||||
|
using json::at;
|
||||||
|
|
||||||
|
const m::room room
|
||||||
|
{
|
||||||
|
at<"room_id"_>(event)
|
||||||
|
};
|
||||||
|
|
||||||
|
const m::event::prev refs{event};
|
||||||
|
const auto count
|
||||||
|
{
|
||||||
|
refs.auth_events_count()
|
||||||
|
};
|
||||||
|
|
||||||
|
if(count > 4)
|
||||||
|
log::dwarning
|
||||||
|
{
|
||||||
|
"Event %s has an unexpected %zu auth_events references",
|
||||||
|
string_view{event.event_id},
|
||||||
|
count,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Vector of contingent event idxs from the event and the present state
|
||||||
|
m::event::idx idxs[9]
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
|
||||||
|
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)),
|
||||||
|
|
||||||
|
at<"type"_>(event) == "m.room.member" &&
|
||||||
|
(membership(event) == "join" || membership(event) == "invite")?
|
||||||
|
room.get(std::nothrow, "m.room.join_rules", ""): 0UL,
|
||||||
|
|
||||||
|
at<"type"_>(event) == "m.room.member" &&
|
||||||
|
at<"sender"_>(event) != at<"state_key"_>(event)?
|
||||||
|
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<bool>(ret) || std::get<std::exception_ptr>(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ircd::m::room::auth::passfail
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::check(std::nothrow_t,
|
||||||
|
const event &event,
|
||||||
|
hookdata &data)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 1. If type is m.room.create:
|
||||||
|
if(json::get<"type"_>(event) == "m.room.create")
|
||||||
|
{
|
||||||
|
room_auth_hook(event, data);
|
||||||
|
return {data.allow, data.fail};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Reject if event has auth_events that:
|
||||||
|
check_room_auth_rule_2(event, data);
|
||||||
|
|
||||||
|
// 3. If event does not have a m.room.create in its auth_events, reject.
|
||||||
|
check_room_auth_rule_3(event, data);
|
||||||
|
|
||||||
|
// 4. If type is m.room.aliases
|
||||||
|
if(json::get<"type"_>(event) == "m.room.aliases")
|
||||||
|
{
|
||||||
|
room_auth_hook(event, data);
|
||||||
|
return {data.allow, data.fail};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. If type is m.room.member
|
||||||
|
if(json::get<"type"_>(event) == "m.room.member")
|
||||||
|
{
|
||||||
|
room_auth_hook(event, data);
|
||||||
|
return {data.allow, data.fail};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. If the sender's current membership state is not join, reject.
|
||||||
|
check_room_auth_rule_6(event, data);
|
||||||
|
|
||||||
|
// 7. If type is m.room.third_party_invite:
|
||||||
|
if(json::get<"type"_>(event) == "m.room.third_party_invite")
|
||||||
|
{
|
||||||
|
room_auth_hook(event, data);
|
||||||
|
return {data.allow, data.fail};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8. If the event type's required power level is greater than the
|
||||||
|
// sender's power level, reject.
|
||||||
|
check_room_auth_rule_8(event, data);
|
||||||
|
|
||||||
|
// 9. If the event has a state_key that starts with an @ and does not
|
||||||
|
// match the sender, reject.
|
||||||
|
check_room_auth_rule_9(event, data);
|
||||||
|
|
||||||
|
// 10. If type is m.room.power_levels:
|
||||||
|
if(json::get<"type"_>(event) == "m.room.power_levels")
|
||||||
|
{
|
||||||
|
room_auth_hook(event, data);
|
||||||
|
return {data.allow, data.fail};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 11. If type is m.room.redaction:
|
||||||
|
if(json::get<"type"_>(event) == "m.room.redaction")
|
||||||
|
{
|
||||||
|
room_auth_hook(event, data);
|
||||||
|
return {data.allow, data.fail};
|
||||||
|
}
|
||||||
|
|
||||||
|
// (non-spec) Call the hook for any types without a branch enumerated
|
||||||
|
// here. The handler will throw on a failure, otherwise fallthrough to
|
||||||
|
// the next rule.
|
||||||
|
room_auth_hook(event, data);
|
||||||
|
|
||||||
|
// 12. Otherwise, allow.
|
||||||
|
data.allow = true;
|
||||||
|
assert(!data.fail);
|
||||||
|
return {data.allow, data.fail};
|
||||||
|
}
|
||||||
|
catch(const FAIL &e)
|
||||||
|
{
|
||||||
|
data.allow = false;
|
||||||
|
data.fail = std::current_exception();
|
||||||
|
return {data.allow, data.fail};
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// m::room::auth internal
|
||||||
|
//
|
||||||
|
|
||||||
|
void
|
||||||
|
ircd::m::check_room_auth_rule_2(const m::event &event,
|
||||||
|
room::auth::hookdata &data)
|
||||||
|
{
|
||||||
|
using FAIL = room::auth::FAIL;
|
||||||
|
|
||||||
|
// 2. Reject if event has auth_events that:
|
||||||
|
for(size_t i(0); i < data.auth_events.size(); ++i)
|
||||||
|
{
|
||||||
|
// a. have duplicate entries for a given type and state_key pair
|
||||||
|
const m::event &a
|
||||||
|
{
|
||||||
|
*data.auth_events.at(i)
|
||||||
|
};
|
||||||
|
|
||||||
|
for(size_t j(0); j < data.auth_events.size(); ++j) if(i != j)
|
||||||
|
{
|
||||||
|
const m::event &b
|
||||||
|
{
|
||||||
|
*data.auth_events.at(j)
|
||||||
|
};
|
||||||
|
|
||||||
|
if(json::get<"type"_>(a) == json::get<"type"_>(b))
|
||||||
|
if(json::get<"state_key"_>(a) == json::get<"state_key"_>(b))
|
||||||
|
throw FAIL
|
||||||
|
{
|
||||||
|
"Duplicate (type,state_key) in auth_events."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// b. have entries whose type and state_key don't match those specified by
|
||||||
|
// the auth events selection algorithm described in the server...
|
||||||
|
const string_view &type
|
||||||
|
{
|
||||||
|
json::get<"type"_>(a)
|
||||||
|
};
|
||||||
|
|
||||||
|
if(type == "m.room.create")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(type == "m.room.power_levels")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(type == "m.room.join_rules")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(type == "m.room.member")
|
||||||
|
{
|
||||||
|
if(json::get<"sender"_>(event) == json::get<"state_key"_>(a))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(json::get<"state_key"_>(event) == json::get<"state_key"_>(a))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw FAIL
|
||||||
|
{
|
||||||
|
"Reference in auth_events is not an auth_event."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ircd::m::check_room_auth_rule_3(const m::event &event,
|
||||||
|
room::auth::hookdata &data)
|
||||||
|
{
|
||||||
|
using FAIL = room::auth::FAIL;
|
||||||
|
|
||||||
|
// 3. If event does not have a m.room.create in its auth_events, reject.
|
||||||
|
if(!data.auth_create)
|
||||||
|
throw FAIL
|
||||||
|
{
|
||||||
|
"Missing m.room.create in auth_events."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ircd::m::check_room_auth_rule_6(const m::event &event,
|
||||||
|
room::auth::hookdata &data)
|
||||||
|
{
|
||||||
|
using FAIL = room::auth::FAIL;
|
||||||
|
|
||||||
|
// 6. If the sender's current membership state is not join, reject.
|
||||||
|
if(data.auth_member_sender)
|
||||||
|
if(membership(*data.auth_member_sender) != "join")
|
||||||
|
throw FAIL
|
||||||
|
{
|
||||||
|
"sender is not joined to room."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ircd::m::check_room_auth_rule_8(const m::event &event,
|
||||||
|
room::auth::hookdata &data)
|
||||||
|
{
|
||||||
|
using FAIL = room::auth::FAIL;
|
||||||
|
|
||||||
|
const m::room::power power
|
||||||
|
{
|
||||||
|
data.auth_power? *data.auth_power : m::event{}, *data.auth_create
|
||||||
|
};
|
||||||
|
|
||||||
|
// 8. If the event type's required power level is greater than the
|
||||||
|
// sender's power level, reject.
|
||||||
|
if(!power(at<"sender"_>(event), "events", at<"type"_>(event), json::get<"state_key"_>(event)))
|
||||||
|
throw FAIL
|
||||||
|
{
|
||||||
|
"sender has insufficient power for event type."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ircd::m::check_room_auth_rule_9(const m::event &event,
|
||||||
|
room::auth::hookdata &data)
|
||||||
|
{
|
||||||
|
using FAIL = room::auth::FAIL;
|
||||||
|
|
||||||
|
// 9. If the event has a state_key that starts with an @ and does not
|
||||||
|
// match the sender, reject.
|
||||||
|
if(startswith(json::get<"state_key"_>(event), '@'))
|
||||||
|
if(at<"state_key"_>(event) != at<"sender"_>(event))
|
||||||
|
throw FAIL
|
||||||
|
{
|
||||||
|
"sender cannot set another user's mxid in a state_key."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::is_power_event(const m::event &event)
|
||||||
|
{
|
||||||
|
if(!json::get<"type"_>(event))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(json::get<"type"_>(event) == "m.room.create")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(json::get<"type"_>(event) == "m.room.power_levels")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(json::get<"type"_>(event) == "m.room.join_rules")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(json::get<"type"_>(event) != "m.room.member")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!json::get<"sender"_>(event) || !json::get<"state_key"_>(event))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(json::get<"sender"_>(event) == json::get<"state_key"_>(event))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(membership(event) == "leave" || membership(event) == "ban")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// room::auth::hookdata
|
||||||
|
//
|
||||||
|
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::hookdata::hookdata(const m::event &event,
|
||||||
|
const vector_view<const m::event *> &auth_events)
|
||||||
|
:prev
|
||||||
|
{
|
||||||
|
event
|
||||||
|
}
|
||||||
|
,auth_events
|
||||||
|
{
|
||||||
|
auth_events
|
||||||
|
}
|
||||||
|
,auth_create
|
||||||
|
{
|
||||||
|
find([](const auto &event)
|
||||||
|
{
|
||||||
|
return json::get<"type"_>(event) == "m.room.create";
|
||||||
|
})
|
||||||
|
}
|
||||||
|
,auth_power
|
||||||
|
{
|
||||||
|
find([](const auto &event)
|
||||||
|
{
|
||||||
|
return json::get<"type"_>(event) == "m.room.power_levels";
|
||||||
|
})
|
||||||
|
}
|
||||||
|
,auth_join_rules
|
||||||
|
{
|
||||||
|
find([](const auto &event)
|
||||||
|
{
|
||||||
|
return json::get<"type"_>(event) == "m.room.join_rules";
|
||||||
|
})
|
||||||
|
}
|
||||||
|
,auth_member_target
|
||||||
|
{
|
||||||
|
find([&event](const auto &auth_event)
|
||||||
|
{
|
||||||
|
return json::get<"type"_>(auth_event) == "m.room.member" &&
|
||||||
|
json::get<"state_key"_>(auth_event) == json::get<"state_key"_>(event);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
,auth_member_sender
|
||||||
|
{
|
||||||
|
find([&event](const auto &auth_event)
|
||||||
|
{
|
||||||
|
return json::get<"type"_>(auth_event) == "m.room.member" &&
|
||||||
|
json::get<"state_key"_>(auth_event) == json::get<"sender"_>(event);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const ircd::m::event *
|
||||||
|
ircd::m::room::auth::hookdata::find(const event::closure_bool &closure)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
for(const auto *const &event : auth_events)
|
||||||
|
if(likely(event) && closure(*event))
|
||||||
|
return event;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// room::auth::refs
|
||||||
|
//
|
||||||
|
|
||||||
|
size_t
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::refs::count()
|
||||||
|
const noexcept
|
||||||
|
{
|
||||||
|
return count(string_view{});
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::refs::count(const string_view &type)
|
||||||
|
const noexcept
|
||||||
|
{
|
||||||
|
size_t ret(0);
|
||||||
|
for_each(type, [&ret](const auto &)
|
||||||
|
{
|
||||||
|
++ret;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::refs::has(const event::idx &idx)
|
||||||
|
const noexcept
|
||||||
|
{
|
||||||
|
return !for_each([&idx](const event::idx &ref)
|
||||||
|
{
|
||||||
|
return ref != idx; // true to continue, false to break
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::refs::has(const string_view &type)
|
||||||
|
const noexcept
|
||||||
|
{
|
||||||
|
bool ret{false};
|
||||||
|
for_each(type, [&ret](const auto &)
|
||||||
|
{
|
||||||
|
ret = true;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::refs::for_each(const closure_bool &closure)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
return for_each(string_view{}, closure);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::refs::for_each(const string_view &type,
|
||||||
|
const closure_bool &closure)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
assert(idx);
|
||||||
|
const event::refs erefs
|
||||||
|
{
|
||||||
|
idx
|
||||||
|
};
|
||||||
|
|
||||||
|
return erefs.for_each(dbs::ref::NEXT_AUTH, [this, &type, &closure]
|
||||||
|
(const event::idx &ref, const dbs::ref &)
|
||||||
|
{
|
||||||
|
bool match;
|
||||||
|
const auto matcher
|
||||||
|
{
|
||||||
|
[&type, &match](const string_view &type_)
|
||||||
|
{
|
||||||
|
match = type == type_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if(type)
|
||||||
|
{
|
||||||
|
if(!m::get(std::nothrow, ref, "type", matcher))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(!match)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(idx != ref);
|
||||||
|
if(!closure(ref))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// room::auth::chain
|
||||||
|
//
|
||||||
|
|
||||||
|
size_t
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::chain::depth()
|
||||||
|
const noexcept
|
||||||
|
{
|
||||||
|
size_t ret(0);
|
||||||
|
for_each([&ret](const auto &)
|
||||||
|
{
|
||||||
|
++ret;
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::chain::has(const string_view &type)
|
||||||
|
const noexcept
|
||||||
|
{
|
||||||
|
bool ret(false);
|
||||||
|
for_each(closure_bool{[&type, &ret]
|
||||||
|
(const auto &idx)
|
||||||
|
{
|
||||||
|
m::get(std::nothrow, idx, "type", [&type, &ret]
|
||||||
|
(const auto &value)
|
||||||
|
{
|
||||||
|
ret = value == type;
|
||||||
|
});
|
||||||
|
|
||||||
|
return !ret;
|
||||||
|
}});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::chain::for_each(const closure &closure)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
return for_each(closure_bool{[&closure]
|
||||||
|
(const auto &idx)
|
||||||
|
{
|
||||||
|
closure(idx);
|
||||||
|
return true;
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::chain::for_each(const closure_bool &closure)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
return chain::for_each(*this, closure);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IRCD_MODULE_EXPORT
|
||||||
|
ircd::m::room::auth::chain::for_each(const auth::chain &c,
|
||||||
|
const closure_bool &closure)
|
||||||
|
{
|
||||||
|
m::event::fetch e, a;
|
||||||
|
std::set<event::idx> ae;
|
||||||
|
std::deque<event::idx> aq {c.idx}; do
|
||||||
|
{
|
||||||
|
const auto idx(aq.front());
|
||||||
|
aq.pop_front();
|
||||||
|
if(!seek(e, idx, std::nothrow))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const m::event::prev prev{e};
|
||||||
|
const auto count(prev.auth_events_count());
|
||||||
|
for(size_t i(0); i < count && i < 4; ++i)
|
||||||
|
{
|
||||||
|
const auto &auth_event_id(prev.auth_event(i));
|
||||||
|
const auto &auth_event_idx(index(auth_event_id, std::nothrow));
|
||||||
|
if(!auth_event_idx)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto it(ae.lower_bound(auth_event_idx));
|
||||||
|
if(it == end(ae) || *it != auth_event_idx)
|
||||||
|
{
|
||||||
|
seek(a, auth_event_idx, std::nothrow);
|
||||||
|
ae.emplace_hint(it, auth_event_idx);
|
||||||
|
if(a.valid)
|
||||||
|
aq.emplace_back(auth_event_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(!aq.empty());
|
||||||
|
|
||||||
|
for(const auto &idx : ae)
|
||||||
|
if(!closure(idx))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -515,7 +515,7 @@ ircd::m::bootstrap::eval_lazy_chain(const json::array &auth_chain)
|
||||||
{
|
{
|
||||||
// Skip all events which aren't power events. We don't need them
|
// Skip all events which aren't power events. We don't need them
|
||||||
// here yet. They can wait until state evaluation later.
|
// here yet. They can wait until state evaluation later.
|
||||||
if(!m::event::auth::is_power_event(event))
|
if(!m::room::auth::is_power_event(event))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Find the member event for the sender of this power event so the
|
// Find the member event for the sender of this power event so the
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
namespace ircd::m
|
namespace ircd::m
|
||||||
{
|
{
|
||||||
static void auth_room_create(const event &, event::auth::hookdata &);
|
static void auth_room_create(const event &, room::auth::hookdata &);
|
||||||
extern hookfn<event::auth::hookdata &> auth_room_create_hookfn;
|
extern hookfn<room::auth::hookdata &> auth_room_create_hookfn;
|
||||||
|
|
||||||
static void created_room(const event &, vm::eval &);
|
static void created_room(const event &, vm::eval &);
|
||||||
extern hookfn<vm::eval &> created_room_hookfn;
|
extern hookfn<vm::eval &> created_room_hookfn;
|
||||||
|
@ -83,16 +83,16 @@ ircd::m::auth_room_create_hookfn
|
||||||
{
|
{
|
||||||
auth_room_create,
|
auth_room_create,
|
||||||
{
|
{
|
||||||
{ "_site", "event.auth" },
|
{ "_site", "room.auth" },
|
||||||
{ "type", "m.room.create" },
|
{ "type", "m.room.create" },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
ircd::m::auth_room_create(const event &event,
|
ircd::m::auth_room_create(const event &event,
|
||||||
event::auth::hookdata &data)
|
room::auth::hookdata &data)
|
||||||
{
|
{
|
||||||
using FAIL = m::event::auth::FAIL;
|
using FAIL = m::room::auth::FAIL;
|
||||||
using conforms = m::event::conforms;
|
using conforms = m::event::conforms;
|
||||||
|
|
||||||
// 1. If type is m.room.create:
|
// 1. If type is m.room.create:
|
||||||
|
|
|
@ -69,7 +69,7 @@ _visible_to_node(const m::event &event,
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Allow auth chain events XXX: this is too broad
|
// Allow auth chain events XXX: this is too broad
|
||||||
if(m::event::auth::is_power_event(event))
|
if(m::room::auth::is_power_event(event))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Allow any event where the state_key string is a user mxid and the server
|
// Allow any event where the state_key string is a user mxid and the server
|
||||||
|
|
|
@ -13,20 +13,20 @@ namespace ircd::m
|
||||||
static void affect_user_room(const event &, vm::eval &);
|
static void affect_user_room(const event &, vm::eval &);
|
||||||
extern m::hookfn<m::vm::eval &> affect_user_room_hookfn;
|
extern m::hookfn<m::vm::eval &> affect_user_room_hookfn;
|
||||||
|
|
||||||
static void auth_room_member_ban(const event &, event::auth::hookdata &);
|
static void auth_room_member_ban(const event &, room::auth::hookdata &);
|
||||||
extern m::hookfn<event::auth::hookdata &> auth_room_member_ban_hookfn;
|
extern m::hookfn<room::auth::hookdata &> auth_room_member_ban_hookfn;
|
||||||
|
|
||||||
static void auth_room_member_leave(const event &, event::auth::hookdata &);
|
static void auth_room_member_leave(const event &, room::auth::hookdata &);
|
||||||
extern m::hookfn<event::auth::hookdata &> auth_room_member_leave_hookfn;
|
extern m::hookfn<room::auth::hookdata &> auth_room_member_leave_hookfn;
|
||||||
|
|
||||||
static void auth_room_member_invite(const event &, event::auth::hookdata &);
|
static void auth_room_member_invite(const event &, room::auth::hookdata &);
|
||||||
extern m::hookfn<event::auth::hookdata &> auth_room_member_invite_hookfn;
|
extern m::hookfn<room::auth::hookdata &> auth_room_member_invite_hookfn;
|
||||||
|
|
||||||
static void auth_room_member_join(const event &, event::auth::hookdata &);
|
static void auth_room_member_join(const event &, room::auth::hookdata &);
|
||||||
extern m::hookfn<event::auth::hookdata &> auth_room_member_join_hookfn;
|
extern m::hookfn<room::auth::hookdata &> auth_room_member_join_hookfn;
|
||||||
|
|
||||||
static void auth_room_member(const event &, event::auth::hookdata &);
|
static void auth_room_member(const event &, room::auth::hookdata &);
|
||||||
extern m::hookfn<event::auth::hookdata &> auth_room_member_hookfn;
|
extern m::hookfn<room::auth::hookdata &> auth_room_member_hookfn;
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::mapi::header
|
ircd::mapi::header
|
||||||
|
@ -94,16 +94,16 @@ ircd::m::auth_room_member_hookfn
|
||||||
{
|
{
|
||||||
auth_room_member,
|
auth_room_member,
|
||||||
{
|
{
|
||||||
{ "_site", "event.auth" },
|
{ "_site", "room.auth" },
|
||||||
{ "type", "m.room.member" },
|
{ "type", "m.room.member" },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
ircd::m::auth_room_member(const m::event &event,
|
ircd::m::auth_room_member(const m::event &event,
|
||||||
event::auth::hookdata &data)
|
room::auth::hookdata &data)
|
||||||
{
|
{
|
||||||
using FAIL = m::event::auth::FAIL;
|
using FAIL = m::room::auth::FAIL;
|
||||||
|
|
||||||
// 5. If type is m.room.member:
|
// 5. If type is m.room.member:
|
||||||
assert(json::get<"type"_>(event) == "m.room.member");
|
assert(json::get<"type"_>(event) == "m.room.member");
|
||||||
|
@ -161,7 +161,7 @@ ircd::m::auth_room_member_join_hookfn
|
||||||
{
|
{
|
||||||
auth_room_member_join,
|
auth_room_member_join,
|
||||||
{
|
{
|
||||||
{ "_site", "event.auth" },
|
{ "_site", "room.auth" },
|
||||||
{ "type", "m.room.member" },
|
{ "type", "m.room.member" },
|
||||||
{ "content",
|
{ "content",
|
||||||
{
|
{
|
||||||
|
@ -172,9 +172,9 @@ ircd::m::auth_room_member_join_hookfn
|
||||||
|
|
||||||
void
|
void
|
||||||
ircd::m::auth_room_member_join(const m::event &event,
|
ircd::m::auth_room_member_join(const m::event &event,
|
||||||
event::auth::hookdata &data)
|
room::auth::hookdata &data)
|
||||||
{
|
{
|
||||||
using FAIL = m::event::auth::FAIL;
|
using FAIL = m::room::auth::FAIL;
|
||||||
|
|
||||||
// b. If membership is join
|
// b. If membership is join
|
||||||
assert(membership(event) == "join");
|
assert(membership(event) == "join");
|
||||||
|
@ -258,7 +258,7 @@ ircd::m::auth_room_member_invite_hookfn
|
||||||
{
|
{
|
||||||
auth_room_member_invite,
|
auth_room_member_invite,
|
||||||
{
|
{
|
||||||
{ "_site", "event.auth" },
|
{ "_site", "room.auth" },
|
||||||
{ "type", "m.room.member" },
|
{ "type", "m.room.member" },
|
||||||
{ "content",
|
{ "content",
|
||||||
{
|
{
|
||||||
|
@ -269,9 +269,9 @@ ircd::m::auth_room_member_invite_hookfn
|
||||||
|
|
||||||
void
|
void
|
||||||
ircd::m::auth_room_member_invite(const m::event &event,
|
ircd::m::auth_room_member_invite(const m::event &event,
|
||||||
event::auth::hookdata &data)
|
room::auth::hookdata &data)
|
||||||
{
|
{
|
||||||
using FAIL = m::event::auth::FAIL;
|
using FAIL = m::room::auth::FAIL;
|
||||||
|
|
||||||
// c. If membership is invite
|
// c. If membership is invite
|
||||||
assert(membership(event) == "invite");
|
assert(membership(event) == "invite");
|
||||||
|
@ -349,7 +349,7 @@ ircd::m::auth_room_member_leave_hookfn
|
||||||
{
|
{
|
||||||
auth_room_member_leave,
|
auth_room_member_leave,
|
||||||
{
|
{
|
||||||
{ "_site", "event.auth" },
|
{ "_site", "room.auth" },
|
||||||
{ "type", "m.room.member" },
|
{ "type", "m.room.member" },
|
||||||
{ "content",
|
{ "content",
|
||||||
{
|
{
|
||||||
|
@ -360,9 +360,9 @@ ircd::m::auth_room_member_leave_hookfn
|
||||||
|
|
||||||
void
|
void
|
||||||
ircd::m::auth_room_member_leave(const m::event &event,
|
ircd::m::auth_room_member_leave(const m::event &event,
|
||||||
event::auth::hookdata &data)
|
room::auth::hookdata &data)
|
||||||
{
|
{
|
||||||
using FAIL = m::event::auth::FAIL;
|
using FAIL = m::room::auth::FAIL;
|
||||||
|
|
||||||
// d. If membership is leave
|
// d. If membership is leave
|
||||||
assert(membership(event) == "leave");
|
assert(membership(event) == "leave");
|
||||||
|
@ -445,7 +445,7 @@ ircd::m::auth_room_member_ban_hookfn
|
||||||
{
|
{
|
||||||
auth_room_member_ban,
|
auth_room_member_ban,
|
||||||
{
|
{
|
||||||
{ "_site", "event.auth" },
|
{ "_site", "room.auth" },
|
||||||
{ "type", "m.room.member" },
|
{ "type", "m.room.member" },
|
||||||
{ "content",
|
{ "content",
|
||||||
{
|
{
|
||||||
|
@ -456,9 +456,9 @@ ircd::m::auth_room_member_ban_hookfn
|
||||||
|
|
||||||
void
|
void
|
||||||
ircd::m::auth_room_member_ban(const m::event &event,
|
ircd::m::auth_room_member_ban(const m::event &event,
|
||||||
event::auth::hookdata &data)
|
room::auth::hookdata &data)
|
||||||
{
|
{
|
||||||
using FAIL = m::event::auth::FAIL;
|
using FAIL = m::room::auth::FAIL;
|
||||||
|
|
||||||
// e. If membership is ban
|
// e. If membership is ban
|
||||||
assert(membership(event) == "ban");
|
assert(membership(event) == "ban");
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
namespace ircd::m
|
namespace ircd::m
|
||||||
{
|
{
|
||||||
static void room_message_auth(const event &, event::auth::hookdata &);
|
static void room_message_auth(const event &, room::auth::hookdata &);
|
||||||
extern hookfn<event::auth::hookdata &> room_message_auth_hook;
|
extern hookfn<room::auth::hookdata &> room_message_auth_hook;
|
||||||
|
|
||||||
static void room_message_notify(const event &, vm::eval &);
|
static void room_message_notify(const event &, vm::eval &);
|
||||||
extern hookfn<vm::eval &> room_message_notify_hook;
|
extern hookfn<vm::eval &> room_message_notify_hook;
|
||||||
|
@ -69,16 +69,16 @@ ircd::m::room_message_auth_hook
|
||||||
{
|
{
|
||||||
room_message_auth,
|
room_message_auth,
|
||||||
{
|
{
|
||||||
{ "_site", "event.auth" },
|
{ "_site", "room.auth" },
|
||||||
{ "type", "m.room.message" },
|
{ "type", "m.room.message" },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
ircd::m::room_message_auth(const event &event,
|
ircd::m::room_message_auth(const event &event,
|
||||||
event::auth::hookdata &data)
|
room::auth::hookdata &data)
|
||||||
{
|
{
|
||||||
using FAIL = m::event::auth::FAIL;
|
using FAIL = m::room::auth::FAIL;
|
||||||
using conforms = m::event::conforms;
|
using conforms = m::event::conforms;
|
||||||
assert(json::get<"type"_>(event) == "m.room.message");
|
assert(json::get<"type"_>(event) == "m.room.message");
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
namespace ircd::m
|
namespace ircd::m
|
||||||
{
|
{
|
||||||
static void auth_room_power_levels(const event &, event::auth::hookdata &);
|
static void auth_room_power_levels(const event &, room::auth::hookdata &);
|
||||||
extern hookfn<event::auth::hookdata &> auth_room_power_levels_hookfn;
|
extern hookfn<room::auth::hookdata &> auth_room_power_levels_hookfn;
|
||||||
|
|
||||||
static void changed_room_power_levels(const event &, vm::eval &);
|
static void changed_room_power_levels(const event &, vm::eval &);
|
||||||
extern m::hookfn<m::vm::eval &> changed_room_power_levels_hookfn;
|
extern m::hookfn<m::vm::eval &> changed_room_power_levels_hookfn;
|
||||||
|
@ -51,16 +51,16 @@ ircd::m::auth_room_power_levels_hookfn
|
||||||
{
|
{
|
||||||
auth_room_power_levels,
|
auth_room_power_levels,
|
||||||
{
|
{
|
||||||
{ "_site", "event.auth" },
|
{ "_site", "room.auth" },
|
||||||
{ "type", "m.room.power_levels" },
|
{ "type", "m.room.power_levels" },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
ircd::m::auth_room_power_levels(const m::event &event,
|
ircd::m::auth_room_power_levels(const m::event &event,
|
||||||
event::auth::hookdata &data)
|
room::auth::hookdata &data)
|
||||||
{
|
{
|
||||||
using FAIL = event::auth::FAIL;
|
using FAIL = room::auth::FAIL;
|
||||||
|
|
||||||
// 10. If type is m.room.power_levels:
|
// 10. If type is m.room.power_levels:
|
||||||
assert(json::get<"type"_>(event) == "m.room.power_levels");
|
assert(json::get<"type"_>(event) == "m.room.power_levels");
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
namespace ircd::m
|
namespace ircd::m
|
||||||
{
|
{
|
||||||
static void auth_room_redaction(const event &, event::auth::hookdata &);
|
static void auth_room_redaction(const event &, room::auth::hookdata &);
|
||||||
extern hookfn<event::auth::hookdata &> auth_room_redaction_hookfn;
|
extern hookfn<room::auth::hookdata &> auth_room_redaction_hookfn;
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::mapi::header
|
ircd::mapi::header
|
||||||
|
@ -25,16 +25,16 @@ ircd::m::auth_room_redaction_hookfn
|
||||||
{
|
{
|
||||||
auth_room_redaction,
|
auth_room_redaction,
|
||||||
{
|
{
|
||||||
{ "_site", "event.auth" },
|
{ "_site", "room.auth" },
|
||||||
{ "type", "m.room.redaction" },
|
{ "type", "m.room.redaction" },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
ircd::m::auth_room_redaction(const m::event &event,
|
ircd::m::auth_room_redaction(const m::event &event,
|
||||||
event::auth::hookdata &data)
|
room::auth::hookdata &data)
|
||||||
{
|
{
|
||||||
using FAIL = event::auth::FAIL;
|
using FAIL = room::auth::FAIL;
|
||||||
|
|
||||||
// 11. If type is m.room.redaction:
|
// 11. If type is m.room.redaction:
|
||||||
assert(json::get<"type"_>(event) == "m.room.redaction");
|
assert(json::get<"type"_>(event) == "m.room.redaction");
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
namespace ircd::m
|
namespace ircd::m
|
||||||
{
|
{
|
||||||
static void auth_room_third_party_invite(const event &, event::auth::hookdata &);
|
static void auth_room_third_party_invite(const event &, room::auth::hookdata &);
|
||||||
extern hookfn<event::auth::hookdata &> auth_room_third_party_invite_hookfn;
|
extern hookfn<room::auth::hookdata &> auth_room_third_party_invite_hookfn;
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::mapi::header
|
ircd::mapi::header
|
||||||
|
@ -29,16 +29,16 @@ ircd::m::auth_room_third_party_invite_hookfn
|
||||||
{
|
{
|
||||||
auth_room_third_party_invite,
|
auth_room_third_party_invite,
|
||||||
{
|
{
|
||||||
{ "_site", "event.auth" },
|
{ "_site", "room.auth" },
|
||||||
{ "type", "m.room.third_party_invite" },
|
{ "type", "m.room.third_party_invite" },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
ircd::m::auth_room_third_party_invite(const event &event,
|
ircd::m::auth_room_third_party_invite(const event &event,
|
||||||
event::auth::hookdata &data)
|
room::auth::hookdata &data)
|
||||||
{
|
{
|
||||||
using FAIL = m::event::auth::FAIL;
|
using FAIL = m::room::auth::FAIL;
|
||||||
|
|
||||||
// 7. If type is m.room.third_party_invite:
|
// 7. If type is m.room.third_party_invite:
|
||||||
assert(json::get<"type"_>(event) == "m.room.third_party_invite");
|
assert(json::get<"type"_>(event) == "m.room.third_party_invite");
|
||||||
|
|
|
@ -424,19 +424,14 @@ ircd::m::vm::inject(eval &eval,
|
||||||
add_auth_events? auth_buf_sz : 0UL
|
add_auth_events? auth_buf_sz : 0UL
|
||||||
};
|
};
|
||||||
|
|
||||||
// Default to an empty array.
|
// Conditionally compose the auth events. efault to an empty array.
|
||||||
json::array auth_events
|
const json::array auth_events
|
||||||
{
|
{
|
||||||
json::empty_array
|
add_auth_events?
|
||||||
|
room::auth::generate(auth_buf, m::room{eval.room_id}, m::event{event}):
|
||||||
|
json::empty_array
|
||||||
};
|
};
|
||||||
|
|
||||||
// Conditionally compose the auth events.
|
|
||||||
if(add_auth_events)
|
|
||||||
{
|
|
||||||
const room::auth auth{room{eval.room_id}};
|
|
||||||
auth_events = auth.make_refs(auth_buf, m::event{event});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conditionally add the auth_events to the event iov.
|
// Conditionally add the auth_events to the event iov.
|
||||||
const json::iov::add auth_events_
|
const json::iov::add auth_events_
|
||||||
{
|
{
|
||||||
|
@ -898,7 +893,7 @@ ircd::m::vm::execute_pdu(eval &eval,
|
||||||
|
|
||||||
// Evaluation by auth system; throws
|
// Evaluation by auth system; throws
|
||||||
if(opts.auth && !internal(room_id))
|
if(opts.auth && !internal(room_id))
|
||||||
event::auth::check(event);
|
room::auth::check(event);
|
||||||
|
|
||||||
// Obtain sequence number here.
|
// Obtain sequence number here.
|
||||||
const auto *const &top(eval::seqmax());
|
const auto *const &top(eval::seqmax());
|
||||||
|
|
Loading…
Add table
Reference in a new issue