diff --git a/include/ircd/m/name.h b/include/ircd/m/name.h index 82e933c10..af59171a0 100644 --- a/include/ircd/m/name.h +++ b/include/ircd/m/name.h @@ -191,6 +191,7 @@ struct ircd::m::name static constexpr const char *const pattern {"pattern"}; static constexpr const char *const is {"is"}; static constexpr const char *const cond {"cond"}; + static constexpr const char *const value {"value"}; static constexpr const char *const actions {"actions"}; static constexpr const char *const default_ {"default"}; diff --git a/include/ircd/m/push.h b/include/ircd/m/push.h index 016416518..c8b997fdf 100644 --- a/include/ircd/m/push.h +++ b/include/ircd/m/push.h @@ -64,8 +64,8 @@ struct ircd::m::push::match struct opts; using cond_kind_func = bool (*)(const event &, const cond &, const opts &); - static const string_view cond_kind_name[6]; - static const cond_kind_func cond_kind[7]; + static const string_view cond_kind_name[]; + static const cond_kind_func cond_kind[]; explicit match(const event &, const cond &, const opts &); explicit match(const event &, const rule &, const opts &); @@ -217,7 +217,11 @@ struct ircd::m::push::cond /// prefixed by one of, ==, <, >, >= or <=. A prefix of < matches rooms /// where the member count is strictly less than the given number and so /// forth. If no prefix is present, this parameter defaults to ==. - json::property + json::property, + + /// Required for event_property conditions. The exact case-sensitive string + /// to match. + json::property > { using super_type::tuple; diff --git a/matrix/name.cc b/matrix/name.cc index 39d55aed3..f5407590c 100644 --- a/matrix/name.cc +++ b/matrix/name.cc @@ -170,6 +170,7 @@ constexpr const char *const ircd::m::name::key; constexpr const char *const ircd::m::name::pattern; constexpr const char *const ircd::m::name::is; constexpr const char *const ircd::m::name::cond; +constexpr const char *const ircd::m::name::value; constexpr const char *const ircd::m::name::actions; constexpr const char *const ircd::m::name::default_; diff --git a/matrix/push.cc b/matrix/push.cc index bff63b6f7..e716b2fd5 100644 --- a/matrix/push.cc +++ b/matrix/push.cc @@ -77,6 +77,7 @@ namespace ircd::m::push static bool state_key_user_mxid(const event &, const cond &, const match::opts &); static bool contains_user_mxid(const event &, const cond &, const match::opts &); static bool room_member_count(const event &, const cond &, const match::opts &); + static bool event_property_is(const event &, const cond &, const match::opts &); static bool event_match(const event &, const cond &, const match::opts &); } @@ -84,6 +85,7 @@ decltype(ircd::m::push::match::cond_kind) ircd::m::push::match::cond_kind { event_match, + event_property_is, room_member_count, contains_user_mxid, state_key_user_mxid, @@ -96,6 +98,7 @@ decltype(ircd::m::push::match::cond_kind_name) ircd::m::push::match::cond_kind_name { "event_match", + "event_property_is", "room_member_count", "contains_user_mxid", "state_key_user_mxid", @@ -220,6 +223,61 @@ catch(const std::exception &e) return false; } +bool +ircd::m::push::event_property_is(const event &event, + const cond &cond, + const match::opts &opts) +try +{ + assert(json::get<"kind"_>(cond) == "event_property_is"); + + const auto &[top, path] + { + split(json::get<"key"_>(cond), '.') + }; + + string_view value + { + json::get(event, top, json::object{}) + }; + + tokens(path, '.', [&value] + (const string_view &key) + { + if(!json::type(value, json::OBJECT)) + return false; + + value = json::object(value)[key]; + if(likely(!json::type(value, json::STRING))) + return true; + + value = json::string(value); + return false; + }); + + const json::value a{value}, b + { + json::get<"value"_>(cond) + }; + + return a == b; +} +catch(const ctx::interrupted &) +{ + throw; +} +catch(const std::exception &e) +{ + log::error + { + log, "Push condition 'event_property_is' %s :%s", + string_view{event.event_id}, + e.what(), + }; + + return false; +} + bool ircd::m::push::contains_user_mxid(const event &event, const cond &cond,