0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-09-27 11:18:51 +02:00

ircd:Ⓜ️ Simplify m::visible(); refactor implementation.

This commit is contained in:
Jason Volk 2019-09-24 14:24:16 -07:00
parent 9cb0f46440
commit 4254960ee1
11 changed files with 178 additions and 200 deletions

View file

@ -17,5 +17,4 @@ namespace ircd::m
// authentication is supplied (m::id cannot be empty because that's
// considered an invalid mxid). In that case the test is for public vis.
bool visible(const event &, const string_view &mxid);
bool visible(const id::event &, const string_view &mxid);
}

View file

@ -1673,46 +1673,6 @@ ircd::m::redacted::prefetch(const event::idx &event_idx)
return refs.prefetch(dbs::ref::M_ROOM_REDACTION);
}
///////////////////////////////////////////////////////////////////////////////
//
// m/visible.h
//
bool
ircd::m::visible(const event::id &event_id,
const string_view &mxid)
{
m::room::id::buf room_id
{
get(event_id, "room_id", room_id)
};
const m::event event
{
json::members
{
{ "event_id", event_id },
{ "room_id", room_id },
}
};
return visible(event, mxid);
}
bool
ircd::m::visible(const event &event,
const string_view &mxid)
{
using prototype = bool (const m::event &, const string_view &);
static mods::import<prototype> call
{
"m_room_history_visibility", "ircd::m::visible"
};
return call(event, mxid);
}
///////////////////////////////////////////////////////////////////////////////
//
// m/presence.h

View file

@ -345,19 +345,28 @@ get_events_from(client &client,
size_t i(0), j(0);
for(; it && i < size_t(events_limit); --it, ++i)
{
if(!visible(it.event_id(), request.user_id))
const m::event &event{*it};
if(!visible(event, request.user_id))
continue;
j += append_event(chunk, *it, it.event_idx(), room_depth, user_room);
const auto &event_idx(it.event_idx());
j += append_event(chunk, event, event_idx, room_depth, user_room);
}
if(!j)
return j;
chunk.~array();
const m::event::id::buf end_token
{
it?
m::event_id(it.event_idx()):
room_head
};
json::stack::member
{
out, "end", it? it.event_id() : room_head
out, "end", end_token
};
return j;

View file

@ -551,13 +551,17 @@ initialsync_room_timeline_events(client &client,
// event_id on the way down in case of renewing the iterator for the
// way back. This is not a big deal but rocksdb should fix their shit.
ssize_t i(0);
m::event::idx event_idx{0};
m::event::id::buf event_id;
m::room::events it{room};
for(; it && i < 10; --it, ++i)
event_id = it.event_id();
{
event_idx = it.event_idx();
event_id = m::event_id(event_idx);
}
if(i > 0 && !it)
it.seek(event_id);
it.seek(event_idx);
if(i > 0)
for(; it && i > -1; ++it, --i)

View file

@ -183,7 +183,7 @@ get__context(client &client,
--before;
if(before)
start = before.event_id();
start = m::event_id(before.event_idx());
else
start = {};
}
@ -223,7 +223,7 @@ get__context(client &client,
++after;
if(after)
end = after.event_id();
end = m::event_id(after.event_idx());
else
end = {};
}

View file

@ -192,9 +192,6 @@ get__initialsync_local(client &client,
room_state.for_each(m::event::id::closure_bool{[&]
(const m::event::id &event_id)
{
if(!visible(event_id, user.user_id))
return true;
const m::event::fetch event
{
event_id, std::nothrow
@ -203,6 +200,9 @@ get__initialsync_local(client &client,
if(!event.valid)
return true;
if(!visible(event, user.user_id))
return true;
m::event::append::opts opts;
opts.event_idx = &event.event_idx;
opts.user_id = &user.user_id;
@ -223,7 +223,7 @@ get__initialsync_local(client &client,
if(it)
json::stack::member
{
messages, "start", it.event_id()
messages, "start", m::event_id(it.event_idx())
};
// seek down first to give events in chronological order.
@ -231,7 +231,7 @@ get__initialsync_local(client &client,
if(it)
json::stack::member
{
messages, "end", it.event_id()
messages, "end", m::event_id(it.event_idx())
};
json::stack::array chunk
@ -241,12 +241,10 @@ get__initialsync_local(client &client,
for(; it; ++it)
{
const auto &event_id(it.event_id());
if(!visible(event_id, user.user_id))
continue;
const m::event &event(*it);
const auto &event_idx(it.event_idx());
const m::event &event(*it);
if(!visible(event, user.user_id))
continue;
m::event::append::opts opts;
opts.event_idx = &event_idx;

View file

@ -7406,12 +7406,17 @@ console_cmd__event__visible(opt &out, const string_view &line)
param[1]
};
const bool visible
const m::event event
{
m::visible(event_id, mxid)
event_id
};
out << event_id << " is "
const bool visible
{
m::visible(event, mxid)
};
out << event.event_id << " is "
<< (visible? "VISIBLE" : "NOT VISIBLE")
<< (mxid? " to " : "")
<< mxid

View file

@ -91,12 +91,6 @@ get__backfill(client &client,
m::head(room_id)
};
if(!visible(event_id, request.node_id))
throw m::ACCESS_DENIED
{
"You are not permitted to view the room at this event."
};
const size_t limit
{
calc_limit(request)

View file

@ -127,9 +127,10 @@ get__backfill_ids(client &client,
size_t count{0};
for(; it && count < limit; ++count, --it)
{
const auto &event_id(it.event_id());
if(!visible(event_id, request.node_id))
continue;
const auto event_id
{
m::event_id(it.event_idx())
};
pdus.append(event_id);
}

View file

@ -44,17 +44,17 @@ handle_get(client &client,
url::decode(event_id, request.parv[0])
};
if(!visible(event_id, request.node_id))
throw m::ACCESS_DENIED
{
"You are not permitted to view this event"
};
const m::event::fetch event
{
event_id
};
if(!visible(event, request.node_id))
throw m::ACCESS_DENIED
{
"You are not permitted to view this event"
};
resource::response::chunked response
{
client, http::OK

View file

@ -8,100 +8,42 @@
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
using namespace ircd;
namespace ircd::m
{
static bool visible_to_node(const room &, const string_view &node_id, const event &);
static bool visible_to_user(const room &, const string_view &history_visibility, const m::user::id &, const event &);
mapi::header
static void changed_history_visibility(const event &, vm::eval &);
extern hookfn<vm::eval &> changed_history_visibility_hookfn;
}
ircd::mapi::header
IRCD_MODULE
{
"Matrix m.room.history_visibility"
};
static bool
_visible_to_user(const m::event &event,
const m::user::id &user_id,
const m::room &room,
const string_view &history_visibility)
decltype(ircd::m::changed_history_visibility_hookfn)
ircd::m::changed_history_visibility_hookfn
{
char membership_buf[m::room::MEMBERSHIP_MAX_SIZE];
string_view membership
changed_history_visibility,
{
m::membership(membership_buf, room, user_id)
{ "_site", "vm.effect" },
{ "type", "m.room.history_visibility" },
}
};
if(membership == "join")
return true;
if(history_visibility == "joined")
return false;
if(history_visibility == "invited")
return membership == "invite";
assert(history_visibility == "shared");
if(membership == "invite")
return true;
// If the room is not at the present event then we have to run another
// test for membership here. Otherwise the "join" test already failed.
if(room.event_id)
void
ircd::m::changed_history_visibility(const event &event,
vm::eval &)
{
const m::room present{room.room_id};
membership = m::membership(membership_buf, present, user_id);
return membership == "join" || membership == "invite";
}
return false;
}
static bool
_visible_to_node(const m::event &event,
const string_view &node_id,
const m::room &room,
const string_view &history_visibility)
log::info
{
const m::room::origins origins
{
room
};
// Allow joined servers
if(origins.has(node_id))
return true;
// Allow auth chain events XXX: this is too broad
if(m::room::auth::is_power_event(event))
return true;
// Allow any event where the state_key string is a user mxid and the server
// is the host of that user. Note that applies to any type of event.
if(m::valid(m::id::USER, json::get<"state_key"_>(event)))
if(m::user::id(at<"state_key"_>(event)).host() == node_id)
return true;
return false;
}
static bool
_visible(const m::event &event,
const string_view &mxid,
const m::room &room,
const string_view &history_visibility)
{
if(history_visibility == "world_readable")
return true;
if(empty(mxid))
return false;
if(m::valid(m::id::USER, mxid))
return _visible_to_user(event, mxid, room, history_visibility);
if(rfc3986::valid_remote(std::nothrow, mxid))
return _visible_to_node(event, mxid, room, history_visibility);
throw m::UNSUPPORTED
{
"Cannot determine visibility for '%s'", mxid
log, "Changed visibility of %s to %s by %s => %s",
json::get<"room_id"_>(event),
json::get<"content"_>(event).get("history_visibility"),
json::get<"sender"_>(event),
string_view{event.event_id},
};
}
@ -115,61 +57,127 @@ ircd::m::visible(const m::event &event,
at<"room_id"_>(event), event.event_id
};
static const m::event::fetch::opts fopts
{
m::event::keys::include{"content"}
};
const m::room::state state
{
room, &fopts
room
};
bool ret{false};
const bool has_state_event
const event::idx visibility_event_idx
{
state.get(std::nothrow, "m.room.history_visibility", "", [&]
(const m::event &visibility_event)
{
const json::object &content
{
json::get<"content"_>(visibility_event)
state.get(std::nothrow, "m.room.history_visibility", "")
};
const string_view &history_visibility
char buf[32];
string_view history_visibility{"shared"};
m::get(std::nothrow, visibility_event_idx, "content", [&buf, &history_visibility]
(const json::object &content)
{
unquote(content.get("history_visibility", "shared"))
const json::string &_history_visibility
{
content.get("history_visibility", "shared")
};
ret = _visible(event, mxid, room, history_visibility);
})
history_visibility = strncpy
{
buf, _history_visibility
};
});
return !has_state_event?
_visible(event, mxid, room, "shared"):
ret;
}
if(history_visibility == "world_readable")
return true;
static void
_changed_visibility(const m::event &event,
m::vm::eval &)
if(empty(mxid))
return false;
if(m::valid(m::id::USER, mxid))
return visible_to_user(room, history_visibility, mxid, event);
if(rfc3986::valid_remote(std::nothrow, mxid))
return visible_to_node(room, mxid, event);
throw m::UNSUPPORTED
{
log::info
{
m::log, "Changed visibility of %s to %s by %s => %s",
json::get<"room_id"_>(event),
json::get<"content"_>(event).get("history_visibility"),
json::get<"sender"_>(event),
string_view{event.event_id}
"Cannot determine visibility of %s for '%s'",
string_view{room.room_id},
mxid,
};
}
m::hookfn<m::vm::eval &>
_changed_visibility_hookfn
bool
ircd::m::visible_to_user(const m::room &room,
const string_view &history_visibility,
const m::user::id &user_id,
const m::event &event)
{
_changed_visibility,
assert(history_visibility != "world_readable");
// Allow any member event where the state_key string is a user mxid.
if(json::get<"type"_>(event) == "m.room.member")
if(at<"state_key"_>(event) == user_id)
return true;
// Get the membership of the user in the room at the event.
char buf[m::room::MEMBERSHIP_MAX_SIZE];
const string_view membership
{
{ "_site", "vm.effect" },
{ "type", "m.room.history_visibility" },
}
m::membership(buf, room, user_id)
};
if(membership == "join")
return true;
if(history_visibility == "joined")
return false;
if(membership == "invite")
return true;
if(history_visibility == "invited")
return false;
// The history_visibility is now likely "shared"; though we cannot assert
// that in case some other string is used for any non-spec customization
// or for graceful forward compatibility. We default to "shared" here.
//assert(history_visibility == "shared");
// An m::room instance with no event_id is used to query the room at the
// present state.
const m::room present
{
room.room_id
};
// If the room is not at the present event then we have to run another
// test for membership here. Otherwise the "join" test already failed.
if(!room.event_id)
return false;
return m::membership(present, user_id, m::membership_positive); // join || invite
}
bool
ircd::m::visible_to_node(const m::room &room,
const string_view &node_id,
const m::event &event)
{
// Allow auth chain events XXX: this is too broad
if(m::room::auth::is_power_event(event))
return true;
// Allow any event where the state_key string is a user mxid and the server
// is the host of that user. Note that applies to any type of event.
if(m::valid(m::id::USER, json::get<"state_key"_>(event)))
if(m::user::id(at<"state_key"_>(event)).host() == node_id)
return true;
const m::room::origins origins
{
room
};
// Allow joined servers
if(origins.has(node_id))
return true;
return false;
}