From d1b07221697c70576a33fa606e5ac62a4df8dcf7 Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Tue, 25 Apr 2023 12:22:26 -0700 Subject: [PATCH] ircd::m::user::keys: Move amalgamated keys and sigs output into central interface. --- include/ircd/m/user/keys.h | 33 +++ include/ircd/m/user/user.h | 2 + matrix/Makefile.am | 1 + matrix/user_keys.cc | 264 +++++++++++++++++++++++ modules/client/keys/signatures/upload.cc | 35 ++- modules/federation/user_keys_query.cc | 216 +------------------ 6 files changed, 324 insertions(+), 227 deletions(-) create mode 100644 include/ircd/m/user/keys.h create mode 100644 matrix/user_keys.cc diff --git a/include/ircd/m/user/keys.h b/include/ircd/m/user/keys.h new file mode 100644 index 000000000..2a4939359 --- /dev/null +++ b/include/ircd/m/user/keys.h @@ -0,0 +1,33 @@ +// The Construct +// +// Copyright (C) The Construct Developers, Authors & Contributors +// Copyright (C) 2016-2023 Jason Volk +// +// 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_USER_KEYS_H + +struct ircd::m::user::keys +{ + static string_view make_sigs_state_key(const mutable_buffer &, const string_view &tgt, const string_view &src); + static std::tuple unmake_sigs_state_key(const string_view &) noexcept; + + m::user::room user_room; + + void attach_sigs(json::stack::object &, const json::object &) const; + bool attach_sigs(json::stack::object &, const event::idx &) const; + + public: + void device(json::stack::object &, const string_view &device_id) const; + void cross_master(json::stack::object &) const; + void cross_self(json::stack::object &) const; + void cross_user(json::stack::object &) const; + + keys(const m::user &user) + :user_room{user} + {} +}; diff --git a/include/ircd/m/user/user.h b/include/ircd/m/user/user.h index 7b6bcb62c..96bfee64b 100644 --- a/include/ircd/m/user/user.h +++ b/include/ircd/m/user/user.h @@ -52,6 +52,7 @@ struct ircd::m::user struct tokens; struct devices; struct reading; + struct keys; using id = m::id::user; using closure = std::function; @@ -105,3 +106,4 @@ const #include "tokens.h" #include "devices.h" #include "reading.h" +#include "keys.h" diff --git a/matrix/Makefile.am b/matrix/Makefile.am index 95f0628c1..ad30b3068 100644 --- a/matrix/Makefile.am +++ b/matrix/Makefile.am @@ -137,6 +137,7 @@ libircd_matrix_la_SOURCES += user_devices.cc libircd_matrix_la_SOURCES += user_events.cc libircd_matrix_la_SOURCES += user_filter.cc libircd_matrix_la_SOURCES += user_ignores.cc +libircd_matrix_la_SOURCES += user_keys.cc libircd_matrix_la_SOURCES += user_mitsein.cc libircd_matrix_la_SOURCES += user_notifications.cc libircd_matrix_la_SOURCES += user_profile.cc diff --git a/matrix/user_keys.cc b/matrix/user_keys.cc new file mode 100644 index 000000000..067b07442 --- /dev/null +++ b/matrix/user_keys.cc @@ -0,0 +1,264 @@ +// The Construct +// +// Copyright (C) The Construct Developers, Authors & Contributors +// Copyright (C) 2016-2023 Jason Volk +// +// 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. + +void +ircd::m::user::keys::cross_user(json::stack::object &out) +const +{ + const auto &user_id + { + user_room.user.user_id + }; + + const auto event_idx + { + user_room.get(std::nothrow, "ircd.cross_signing.user", "") + }; + + m::get(std::nothrow, event_idx, "content", [&out, &user_id] + (const json::object &content) + { + json::stack::member + { + out, user_id, content + }; + }); +} + +void +ircd::m::user::keys::cross_self(json::stack::object &out) +const +{ + const auto &user_id + { + user_room.user.user_id + }; + + const auto event_idx + { + user_room.get(std::nothrow, "ircd.cross_signing.self", "") + }; + + m::get(std::nothrow, event_idx, "content", [&out, &user_id] + (const json::object &content) + { + json::stack::member + { + out, user_id, content + }; + }); +} + +void +ircd::m::user::keys::cross_master(json::stack::object &out) +const +{ + const auto event_idx + { + user_room.get(std::nothrow, "ircd.cross_signing.master", "") + }; + + m::get(std::nothrow, event_idx, "content", [this, &out] + (const json::object &device_keys) + { + const auto &user_id + { + user_room.user.user_id + }; + + json::stack::object object + { + out, user_id + }; + + for(const auto &member : device_keys) + if(member.first != "signatures") + json::stack::member + { + object, member + }; + + json::stack::object sigs + { + object, "signatures" + }; + + json::stack::object user_sigs + { + sigs, user_id + }; + + attach_sigs(user_sigs, device_keys); + const json::object device_keys_keys + { + device_keys["keys"] + }; + + const m::room::state state + { + user_room + }; + + state.for_each("ircd.keys.signatures", [this, &user_sigs, &device_keys_keys] + (const string_view &, const string_view &state_key, const auto &event_idx) + { + for(const auto &[key_id_, key] : device_keys_keys) + { + const auto &key_id + { + split(key_id_, ':').second + }; + + const auto &[target, source] + { + unmake_sigs_state_key(state_key) + }; + + if(target != key_id) + continue; + + attach_sigs(user_sigs, event_idx); + } + + return true; + }); + }); +} + +void +ircd::m::user::keys::device(json::stack::object &object, + const string_view &device_id) +const +{ + const m::user::devices devices + { + user_room.user + }; + + devices.get(std::nothrow, device_id, "keys", [this, &object, &device_id] + (const auto &, const json::object &device_keys) + { + const auto &user_id + { + user_room.user.user_id + }; + + for(const auto &member : device_keys) + if(member.first != "signatures") + json::stack::member + { + object, member + }; + + json::stack::object sigs + { + object, "signatures" + }; + + json::stack::object user_sigs + { + sigs, user_id + }; + + attach_sigs(user_sigs, device_keys); + const m::room::state state + { + user_room + }; + + state.for_each("ircd.keys.signatures", [this, &user_sigs, &device_id] + (const string_view &, const string_view &state_key, const auto &event_idx) + { + const auto &[target, source] + { + unmake_sigs_state_key(state_key) + }; + + if(target && target != device_id) + return true; + + attach_sigs(user_sigs, event_idx); + return true; + }); + }); +} + +bool +ircd::m::user::keys::attach_sigs(json::stack::object &user_sigs, + const event::idx &event_idx) +const +{ + return m::get(std::nothrow, event_idx, "content", [this, &user_sigs] + (const json::object &device_sigs) + { + attach_sigs(user_sigs, device_sigs); + }); +} + +void +ircd::m::user::keys::attach_sigs(json::stack::object &user_sigs, + const json::object &device_sigs) +const +{ + const auto &user_id + { + user_room.user.user_id + }; + + const json::object device_sigs_sigs + { + device_sigs["signatures"] + }; + + const json::object device_sigs_user_sigs + { + device_sigs_sigs[user_id] + }; + + for(const auto &member : device_sigs_user_sigs) + json::stack::member + { + user_sigs, member + }; +} + +// +// user::keys::sigs +// + +std::tuple +ircd::m::user::keys::unmake_sigs_state_key(const string_view &state_key) +noexcept +{ + const auto &[tgt, src] + { + rsplit(state_key, '%') + }; + + return std::tuple + { + tgt, src + }; +} + +ircd::string_view +ircd::m::user::keys::make_sigs_state_key(const mutable_buffer &buf, + const string_view &tgt, + const string_view &src) +{ + return fmt::sprintf + { + buf, "%s%s", + string_view{tgt}, + tgt != src && src? + string_view{src}: + string_view{}, + }; +} diff --git a/modules/client/keys/signatures/upload.cc b/modules/client/keys/signatures/upload.cc index a3d406e2c..cf7ac9161 100644 --- a/modules/client/keys/signatures/upload.cc +++ b/modules/client/keys/signatures/upload.cc @@ -43,42 +43,35 @@ ircd::m::resource::response ircd::m::post_keys_signatures_upload(client &client, const resource::request &request) { - const auto src_device + const auto src_dev { - m::user::tokens::device(std::nothrow, request.access_token) + user::tokens::device(std::nothrow, request.access_token) }; - for(const auto &[_user_id, devices_keys_] : request) + for(const auto &[user_id, device_keys_] : request) { - if(!valid(m::id::USER, _user_id)) + if(!valid(m::id::USER, user_id)) continue; - const m::user::id user_id + const json::object device_keys { - _user_id + device_keys_ }; - const m::user::room user_room + const user::room user_room { - user_id + user::id{user_id} }; - for(const auto &[target_id, device_keys] : json::object(devices_keys_)) + for(const auto &[tgt_id, keys] : device_keys) { - char buf[512]; - const string_view state_key{fmt::sprintf + char state_key_buf[512]; + const string_view state_key { - buf, "%s%s", - string_view{target_id}, - target_id != src_device && src_device? - string_view{src_device}: - string_view{}, - }}; + user::keys::make_sigs_state_key(state_key_buf, tgt_id, src_dev) + }; - send(user_room, user_id, "ircd.keys.signatures", state_key, json::object - { - device_keys - }); + send(user_room, user_id, "ircd.keys.signatures", state_key, keys); } } diff --git a/modules/federation/user_keys_query.cc b/modules/federation/user_keys_query.cc index 8e911c9b5..544e47414 100644 --- a/modules/federation/user_keys_query.cc +++ b/modules/federation/user_keys_query.cc @@ -155,105 +155,12 @@ _query_master_keys(client &client, user_id_ }; - const m::user::room user_room + const m::user::keys keys { user_id }; - const auto event_idx - { - user_room.get(std::nothrow, "ircd.cross_signing.master", "") - }; - - m::get(std::nothrow, event_idx, "content", [&user_room, &user_id, &response_keys] - (const json::object &device_keys) - { - json::stack::object object - { - response_keys, user_id - }; - - for(const auto &member : device_keys) - if(member.first != "signatures") - json::stack::member - { - object, member - }; - - const json::object device_keys_sigs - { - device_keys["signatures"] - }; - - json::stack::object sigs - { - object, "signatures" - }; - - json::stack::object user_sigs - { - sigs, user_id - }; - - const json::object device_keys_user_sigs - { - device_keys_sigs[user_id] - }; - - for(const auto &member : device_keys_user_sigs) - json::stack::member - { - user_sigs, member - }; - - const m::room::state state - { - user_room - }; - - for(const auto &[key_id__, key] : json::object(device_keys["keys"])) - { - const auto &[algo, key_id_] - { - split(key_id__, ':') - }; - - const auto key_id(key_id_); - state.for_each("ircd.keys.signatures", [&user_id, &user_sigs, &key_id] - (const string_view &, const string_view &state_key, const auto &event_idx) - { - const auto &[target, source] - { - rsplit(state_key, '%') - }; - - if(target != key_id) - return true; - - m::get(std::nothrow, event_idx, "content", [&user_id, &user_sigs] - (const json::object &device_sigs) - { - const json::object device_sigs_sigs - { - device_sigs["signatures"] - }; - - const json::object device_sigs_user_sigs - { - device_sigs_sigs[user_id] - }; - - for(const auto &member : device_sigs_user_sigs) - json::stack::member - { - user_sigs, member - }; - }); - - return true; - }); - } - }); + keys.cross_master(response_keys); } } @@ -279,24 +186,12 @@ _query_self_keys(client &client, user_id_ }; - const m::user::room room + const m::user::keys keys { user_id }; - const auto event_idx - { - room.get(std::nothrow, "ircd.cross_signing.self", "") - }; - - m::get(std::nothrow, event_idx, "content", [&response_keys, &user_id] - (const json::object &content) - { - json::stack::member - { - response_keys, user_id, content - }; - }); + keys.cross_self(response_keys); } } @@ -322,24 +217,12 @@ _query_user_keys(client &client, user_id_ }; - const m::user::room room + const m::user::keys keys { user_id }; - const auto event_idx - { - room.get(std::nothrow, "ircd.cross_signing.user", "") - }; - - m::get(std::nothrow, event_idx, "content", [&response_keys, &user_id] - (const json::object &content) - { - json::stack::member - { - response_keys, user_id, content - }; - }); + keys.cross_user(response_keys); } } @@ -353,96 +236,17 @@ _query_user_device(client &client, if(!devices.has(device_id, "keys")) return; - const m::user::room user_room - { - devices.user.user_id - }; - json::stack::object object { out, device_id }; - devices.get(std::nothrow, device_id, "keys", [&user_room, &device_id, &object] - (const auto &, const json::object &device_keys) + const m::user::keys keys { - const auto &user_id - { - user_room.user.user_id - }; + devices.user + }; - for(const auto &member : device_keys) - if(member.first != "signatures") - json::stack::member - { - object, member - }; - - json::stack::object sigs - { - object, "signatures" - }; - - json::stack::object user_sigs - { - sigs, user_id - }; - - const json::object device_keys_sigs - { - device_keys["signatures"] - }; - - const json::object device_keys_user_sigs - { - device_keys_sigs[user_id] - }; - - for(const auto &member : device_keys_user_sigs) - json::stack::member - { - user_sigs, member - }; - - const m::room::state state - { - user_room - }; - - state.for_each("ircd.keys.signatures", [&user_id, &user_sigs, &device_id] - (const string_view &, const string_view &state_key, const auto &event_idx) - { - const auto &[target, source] - { - rsplit(state_key, '%') - }; - - if(target && target != device_id) - return true; - - m::get(std::nothrow, event_idx, "content", [&user_id, &user_sigs] - (const json::object &device_sigs) - { - const json::object device_sigs_sigs - { - device_sigs["signatures"] - }; - - const json::object device_sigs_user_sigs - { - device_sigs_sigs[user_id] - }; - - for(const auto &member : device_sigs_user_sigs) - json::stack::member - { - user_sigs, member - }; - }); - - return true; - }); - }); + keys.device(object, device_id); devices.get(std::nothrow, device_id, "display_name", [&device_id, &object] (const auto &event_idx, const string_view &display_name)