2019-08-03 01:56:18 +02:00
|
|
|
// 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.
|
|
|
|
|
2023-04-29 05:35:54 +02:00
|
|
|
[[gnu::visibility("hidden")]]
|
|
|
|
decltype(ircd::m::event::append::log)
|
|
|
|
ircd::m::event::append::log
|
2019-08-04 05:53:37 +02:00
|
|
|
{
|
|
|
|
"m.event.append"
|
|
|
|
};
|
|
|
|
|
2023-04-29 05:35:54 +02:00
|
|
|
[[gnu::visibility("hidden")]]
|
|
|
|
decltype(ircd::m::event::append::info)
|
|
|
|
ircd::m::event::append::info
|
2019-08-05 04:10:26 +02:00
|
|
|
{
|
2019-08-05 04:47:51 +02:00
|
|
|
{ "name", "ircd.m.event.append.info" },
|
|
|
|
{ "default", false },
|
|
|
|
{ "persist", false },
|
2019-08-05 04:10:26 +02:00
|
|
|
};
|
|
|
|
|
2023-04-29 05:35:54 +02:00
|
|
|
[[gnu::visibility("hidden")]]
|
|
|
|
decltype(ircd::m::event::append::exclude_types)
|
|
|
|
ircd::m::event::append::exclude_types
|
2023-02-22 03:36:58 +01:00
|
|
|
{
|
|
|
|
{ "name", "ircd.m.event.append.exclude.types" },
|
|
|
|
{ "default", "org.matrix.dummy_event" },
|
|
|
|
};
|
|
|
|
|
2019-08-06 02:24:33 +02:00
|
|
|
/// Default event property mask of keys which we strip from the event sent
|
|
|
|
/// to the client. This mask is applied only if the caller of event::append{}
|
|
|
|
/// did not supply their mask to apply. It is also inferior to the user's
|
|
|
|
/// filter if supplied.
|
2023-04-29 05:35:54 +02:00
|
|
|
[[gnu::visibility("hidden")]]
|
|
|
|
decltype(ircd::m::event::append::exclude_keys)
|
|
|
|
ircd::m::event::append::exclude_keys
|
2019-08-06 02:24:33 +02:00
|
|
|
{
|
|
|
|
"auth_events",
|
|
|
|
"hashes",
|
|
|
|
"membership",
|
|
|
|
"origin",
|
|
|
|
"prev_state",
|
|
|
|
"signatures",
|
|
|
|
};
|
|
|
|
|
2023-04-29 05:35:54 +02:00
|
|
|
[[gnu::visibility("hidden")]]
|
|
|
|
decltype(ircd::m::event::append::default_keys)
|
|
|
|
ircd::m::event::append::default_keys
|
2019-08-06 02:24:33 +02:00
|
|
|
{
|
2023-04-29 05:35:54 +02:00
|
|
|
event::append::exclude_keys
|
2019-08-06 02:24:33 +02:00
|
|
|
};
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
bool
|
|
|
|
ircd::m::event::append::object(json::stack::array &array,
|
|
|
|
const event &event,
|
2019-08-03 01:56:18 +02:00
|
|
|
const opts &opts)
|
|
|
|
{
|
2020-04-15 00:23:22 +02:00
|
|
|
assert(array.s);
|
|
|
|
json::stack::checkpoint cp
|
|
|
|
{
|
|
|
|
*array.s
|
|
|
|
};
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
json::stack::object _object
|
2019-08-03 01:56:18 +02:00
|
|
|
{
|
|
|
|
array
|
|
|
|
};
|
|
|
|
|
|
|
|
const bool ret
|
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
members(_object, event, opts)
|
2019-08-03 01:56:18 +02:00
|
|
|
};
|
|
|
|
|
2020-04-15 00:23:22 +02:00
|
|
|
cp.committing(ret);
|
2019-08-03 01:56:18 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
bool
|
|
|
|
ircd::m::event::append::members(json::stack::object &out,
|
|
|
|
const event &event,
|
|
|
|
const opts &opts)
|
2019-08-03 01:56:18 +02:00
|
|
|
{
|
2019-08-10 06:17:23 +02:00
|
|
|
// Assertions that the event being appended has some required fields. This
|
|
|
|
// is a central butt-end test of data coming through the system to here.
|
|
|
|
assert(event.event_id);
|
|
|
|
assert(defined(json::get<"type"_>(event)));
|
|
|
|
assert(defined(json::get<"sender"_>(event)));
|
|
|
|
//assert(json::get<"origin_server_ts"_>(event));
|
|
|
|
//assert(json::get<"origin_server_ts"_>(event) != json::undefined_number);
|
2023-04-29 21:35:03 +02:00
|
|
|
if constexpr(RB_DEBUG_LEVEL)
|
|
|
|
{
|
|
|
|
if(unlikely(!defined(json::get<"type"_>(event))))
|
|
|
|
return false;
|
2020-01-18 02:27:34 +01:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
if(unlikely(!defined(json::get<"sender"_>(event))))
|
|
|
|
return false;
|
|
|
|
}
|
2020-12-28 09:00:00 +01:00
|
|
|
|
|
|
|
if(opts.event_filter && !m::match(*opts.event_filter, event))
|
|
|
|
return false;
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
if(is_excluded(event, opts))
|
|
|
|
return false;
|
2023-02-22 03:36:58 +01:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
if(is_invisible(event, opts))
|
2023-02-22 03:36:58 +01:00
|
|
|
return false;
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
if(is_redacted(event, opts))
|
|
|
|
return false;
|
2020-12-28 09:56:45 +01:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
if(is_ignored(event, opts))
|
2020-12-28 09:56:45 +01:00
|
|
|
return false;
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
// For v3+ events
|
|
|
|
if(!json::get<"event_id"_>(event))
|
|
|
|
json::stack::member
|
|
|
|
{
|
|
|
|
out, "event_id", event.event_id
|
|
|
|
};
|
2019-08-10 06:17:23 +02:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
// Get the list of properties to send to the client so we can strip
|
|
|
|
// the remaining and save b/w
|
|
|
|
// TODO: m::filter
|
|
|
|
const event::keys &keys
|
2019-09-16 04:34:16 +02:00
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
opts.keys?
|
|
|
|
*opts.keys:
|
|
|
|
default_keys
|
2019-09-16 04:34:16 +02:00
|
|
|
};
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
// Append the event members
|
|
|
|
for_each(event, [&keys, &out]
|
|
|
|
(const auto &key, const auto &val_)
|
2019-09-18 00:26:28 +02:00
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
if(!keys.has(key) && key != "redacts"_sv)
|
|
|
|
return true;
|
2019-09-18 00:26:28 +02:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
const json::value val
|
2019-08-03 01:56:18 +02:00
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
val_
|
2019-08-03 01:56:18 +02:00
|
|
|
};
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
if(!defined(val))
|
|
|
|
return true;
|
2019-09-18 00:26:40 +02:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
json::stack::member
|
2019-09-16 04:34:16 +02:00
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
out, key, val
|
2019-09-16 04:34:16 +02:00
|
|
|
};
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
|
|
|
_unsigned(out, event, opts);
|
|
|
|
|
|
|
|
if(unlikely(info))
|
|
|
|
log::info
|
2019-08-03 01:56:18 +02:00
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
log, "%s %s idx:%lu in %s depth:%ld txnid:%s %s,%s",
|
|
|
|
string_view{opts.user_id},
|
|
|
|
string_view{event.event_id},
|
|
|
|
opts.event_idx,
|
|
|
|
json::get<"room_id"_>(event),
|
|
|
|
json::get<"depth"_>(event),
|
|
|
|
opts.client_txnid,
|
|
|
|
json::get<"type"_>(event),
|
|
|
|
json::get<"state_key"_>(event),
|
|
|
|
};
|
2019-08-03 01:56:18 +02:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
return true;
|
|
|
|
}
|
2019-08-03 01:56:18 +02:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
void
|
|
|
|
ircd::m::event::append::_unsigned(json::stack::object &out,
|
|
|
|
const event &event,
|
|
|
|
const opts &opts)
|
|
|
|
{
|
|
|
|
json::stack::object object
|
2020-12-28 09:00:00 +01:00
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
out, "unsigned"
|
2020-12-28 09:00:00 +01:00
|
|
|
};
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
_age(object, event, opts);
|
|
|
|
_txnid(object, event, opts);
|
2020-12-28 09:00:00 +01:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
if(defined(json::get<"state_key"_>(event)))
|
|
|
|
_prev_state(object, event, opts);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ircd::m::event::append::_prev_state(json::stack::object &out,
|
|
|
|
const event &event,
|
|
|
|
const opts &opts)
|
|
|
|
{
|
|
|
|
assert(defined(json::get<"state_key"_>(event)))
|
2020-12-28 09:00:00 +01:00
|
|
|
|
2023-02-22 19:35:33 +01:00
|
|
|
const bool query_prev_state
|
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
true
|
|
|
|
&& opts.event_idx
|
|
|
|
&& opts.query_prev_state
|
2023-02-22 19:35:33 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
const auto prev_state_idx
|
|
|
|
{
|
|
|
|
query_prev_state?
|
2023-04-29 21:35:03 +02:00
|
|
|
room::state::prev(opts.event_idx):
|
2023-02-22 19:35:33 +01:00
|
|
|
0UL
|
|
|
|
};
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
if(prev_state_idx)
|
|
|
|
{
|
|
|
|
m::get(std::nothrow, prev_state_idx, "content", [&out]
|
|
|
|
(const json::object &content)
|
2020-12-28 09:00:00 +01:00
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
json::stack::member
|
|
|
|
{
|
|
|
|
out, "prev_content", content
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
const auto replaces_state_id
|
|
|
|
{
|
|
|
|
m::event_id(std::nothrow, prev_state_idx)
|
2020-12-28 09:00:00 +01:00
|
|
|
};
|
|
|
|
|
2019-08-06 02:24:33 +02:00
|
|
|
json::stack::member
|
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
out, "replaces_state", json::value
|
|
|
|
{
|
|
|
|
replaces_state_id?
|
|
|
|
string_view{replaces_state_id}:
|
|
|
|
string_view{}
|
|
|
|
}
|
2019-08-06 02:24:33 +02:00
|
|
|
};
|
2023-04-29 21:35:03 +02:00
|
|
|
}
|
|
|
|
}
|
2019-08-06 02:24:33 +02:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
void
|
|
|
|
ircd::m::event::append::_txnid(json::stack::object &out,
|
|
|
|
const event &event,
|
|
|
|
const opts &opts)
|
|
|
|
{
|
|
|
|
const bool sender_is_user
|
2019-08-03 01:56:18 +02:00
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
json::get<"sender"_>(event) == opts.user_id
|
2019-08-06 02:24:33 +02:00
|
|
|
};
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
const bool query_txnid
|
2019-08-06 02:24:33 +02:00
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
true
|
|
|
|
&& !opts.client_txnid
|
|
|
|
&& opts.query_txnid
|
|
|
|
&& opts.user_room_id
|
|
|
|
&& sender_is_user
|
|
|
|
};
|
2019-08-06 02:24:33 +02:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
const auto txnid_idx
|
|
|
|
{
|
|
|
|
query_txnid?
|
|
|
|
m::room(opts.user_room_id).get(std::nothrow, "ircd.client.txnid", event.event_id):
|
|
|
|
0UL
|
|
|
|
};
|
|
|
|
|
|
|
|
if constexpr(RB_DEBUG_LEVEL)
|
|
|
|
{
|
|
|
|
const bool missing_txnid
|
2019-08-06 02:24:33 +02:00
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
true
|
|
|
|
&& !opts.client_txnid
|
|
|
|
&& !txnid_idx
|
|
|
|
&& sender_is_user
|
|
|
|
&& opts.query_txnid
|
2019-08-06 02:24:33 +02:00
|
|
|
};
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
if(unlikely(missing_txnid))
|
|
|
|
log::dwarning
|
|
|
|
{
|
|
|
|
log, "Could not find transaction_id for %s from %s in %s",
|
|
|
|
string_view{event.event_id},
|
|
|
|
json::get<"sender"_>(event),
|
|
|
|
json::get<"room_id"_>(event)
|
|
|
|
};
|
|
|
|
}
|
2019-08-06 02:24:33 +02:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
if(opts.client_txnid)
|
2019-08-06 02:24:33 +02:00
|
|
|
json::stack::member
|
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
out, "transaction_id", opts.client_txnid
|
2019-08-06 02:24:33 +02:00
|
|
|
};
|
2023-04-29 21:35:03 +02:00
|
|
|
else if(txnid_idx)
|
|
|
|
m::get(std::nothrow, txnid_idx, "content", [&out]
|
|
|
|
(const json::object &content)
|
|
|
|
{
|
|
|
|
json::stack::member
|
|
|
|
{
|
|
|
|
out, "transaction_id", content.get("transaction_id")
|
|
|
|
};
|
|
|
|
});
|
|
|
|
}
|
2019-08-06 02:24:33 +02:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
void
|
|
|
|
ircd::m::event::append::_age(json::stack::object &out,
|
|
|
|
const event &event,
|
|
|
|
const opts &opts)
|
|
|
|
{
|
2019-08-04 05:53:37 +02:00
|
|
|
const json::value age
|
|
|
|
{
|
|
|
|
// When the opts give an explicit age, use it.
|
|
|
|
opts.age != std::numeric_limits<long>::min()?
|
|
|
|
opts.age:
|
|
|
|
|
|
|
|
// If we have depth information, craft a value based on the
|
|
|
|
// distance to the head depth; if this is 0 in riot the event will
|
|
|
|
// "stick" at the bottom of the timeline. This may be advantageous
|
|
|
|
// in the future but for now we make sure the result is non-zero.
|
2023-04-29 21:35:03 +02:00
|
|
|
json::get<"depth"_>(event) >= 0 && opts.room_depth >= 0L?
|
|
|
|
(opts.room_depth + 1 - json::get<"depth"_>(event)) + 1:
|
2019-08-04 05:53:37 +02:00
|
|
|
|
|
|
|
// We don't have depth information, so we use the origin_server_ts.
|
|
|
|
// It is bad if it conflicts with other appends in the room which
|
|
|
|
// did have depth information.
|
2023-04-29 21:35:03 +02:00
|
|
|
opts.room_depth < 0 && json::get<"origin_server_ts"_>(event)?
|
2019-08-04 05:53:37 +02:00
|
|
|
ircd::time<milliseconds>() - json::get<"origin_server_ts"_>(event):
|
|
|
|
|
|
|
|
// Finally, this special value will eliminate the age altogether
|
|
|
|
// during serialization.
|
|
|
|
json::undefined_number
|
|
|
|
};
|
|
|
|
|
2019-08-03 01:56:18 +02:00
|
|
|
json::stack::member
|
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
out, "age", age
|
2019-08-03 01:56:18 +02:00
|
|
|
};
|
2023-04-29 21:35:03 +02:00
|
|
|
}
|
2019-08-03 01:56:18 +02:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
bool
|
|
|
|
ircd::m::event::append::is_excluded(const event &event,
|
|
|
|
const opts &opts)
|
|
|
|
const
|
|
|
|
{
|
|
|
|
const auto ¬_types
|
|
|
|
{
|
|
|
|
exclude_types
|
|
|
|
};
|
|
|
|
|
|
|
|
const bool ret
|
|
|
|
{
|
|
|
|
true
|
|
|
|
&& !opts.event_filter
|
|
|
|
&& token_exists(not_types, ' ', json::get<"type"_>(event))
|
|
|
|
};
|
|
|
|
|
|
|
|
if(ret)
|
|
|
|
log::debug
|
2019-08-03 01:56:18 +02:00
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
log, "Not sending event %s because type '%s' excluded by configuration.",
|
|
|
|
string_view{event.event_id},
|
|
|
|
json::get<"type"_>(event),
|
2019-08-03 01:56:18 +02:00
|
|
|
};
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
return ret;
|
|
|
|
}
|
2019-08-03 01:56:18 +02:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
bool
|
|
|
|
ircd::m::event::append::is_invisible(const event &event,
|
|
|
|
const opts &opts)
|
|
|
|
const
|
|
|
|
{
|
|
|
|
const bool ret
|
2023-02-28 21:17:22 +01:00
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
true
|
|
|
|
&& opts.query_visible
|
|
|
|
&& opts.user_id
|
|
|
|
&& !visible(event, opts.user_id)
|
|
|
|
};
|
2023-02-22 19:35:33 +01:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
if(ret)
|
|
|
|
log::debug
|
2023-02-28 21:17:22 +01:00
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
log, "Not sending event %s because not visible to %s.",
|
|
|
|
string_view{event.event_id},
|
|
|
|
string_view{opts.user_id},
|
2023-02-28 21:17:22 +01:00
|
|
|
};
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ircd::m::event::append::is_redacted(const event &event,
|
|
|
|
const opts &opts)
|
|
|
|
const
|
|
|
|
{
|
|
|
|
const bool ret
|
|
|
|
{
|
|
|
|
true
|
|
|
|
&& opts.event_idx
|
|
|
|
&& opts.query_redacted
|
|
|
|
&& !defined(json::get<"state_key"_>(event))
|
|
|
|
&& opts.room_depth > json::get<"depth"_>(event)
|
|
|
|
&& m::redacted(opts.event_idx)
|
|
|
|
};
|
|
|
|
|
|
|
|
if(ret)
|
|
|
|
log::debug
|
2023-02-28 21:17:22 +01:00
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
log, "Not sending event %s because redacted.",
|
|
|
|
string_view{event.event_id},
|
2023-02-28 21:17:22 +01:00
|
|
|
};
|
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ircd::m::event::append::is_ignored(const event &event,
|
|
|
|
const opts &opts)
|
|
|
|
const
|
|
|
|
{
|
|
|
|
const bool check_ignores
|
|
|
|
{
|
|
|
|
true
|
|
|
|
&& !defined(json::get<"state_key"_>(event))
|
|
|
|
&& opts.user_id
|
|
|
|
&& opts.user_room_id
|
|
|
|
&& opts.user_id != json::get<"sender"_>(event)
|
|
|
|
};
|
|
|
|
|
|
|
|
if(!check_ignores)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const m::user::ignores ignores
|
|
|
|
{
|
|
|
|
opts.user_id
|
|
|
|
};
|
|
|
|
|
|
|
|
if(ignores.enforce("events") && ignores.has(json::get<"sender"_>(event)))
|
|
|
|
{
|
|
|
|
log::debug
|
2019-08-05 04:10:26 +02:00
|
|
|
{
|
2023-04-29 21:35:03 +02:00
|
|
|
log, "Not sending event %s because %s is ignored by %s",
|
2019-08-05 04:10:26 +02:00
|
|
|
string_view{event.event_id},
|
2023-04-29 21:35:03 +02:00
|
|
|
json::get<"sender"_>(event),
|
|
|
|
string_view{opts.user_id}
|
2019-08-05 04:10:26 +02:00
|
|
|
};
|
2019-08-04 05:53:37 +02:00
|
|
|
|
2023-04-29 21:35:03 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2019-08-03 01:56:18 +02:00
|
|
|
}
|