0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-30 10:42:47 +01:00
construct/modules/key/query.cc

190 lines
3.9 KiB
C++

// The Construct
//
// Copyright (C) The Construct Developers, Authors & Contributors
// Copyright (C) 2016-2020 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 resource::response handle_key_query_get(client &, const resource::request &);
extern resource::method key_query_get;
static resource::response handle_key_query_post(client &, const resource::request &);
extern resource::method key_query_post;
extern resource key_query_resource;
}
ircd::mapi::header
IRCD_MODULE
{
"Federation 3.3.2 :Querying Keys Through Another Server"
};
decltype(ircd::m::key_query_resource)
ircd::m::key_query_resource
{
"/_matrix/key/v2/query/",
{
"federation 3.3.2",
resource::DIRECTORY,
}
};
decltype(ircd::m::key_query_post)
ircd::m::key_query_post
{
key_query_resource, "POST", handle_key_query_post
};
ircd::m::resource::response
ircd::m::handle_key_query_post(client &client,
const m::resource::request &request)
{
const json::object &server_keys_request
{
request["server_keys"]
};
resource::response::chunked response
{
client, http::OK
};
json::stack out
{
response.buf, response.flusher()
};
json::stack::object top{out};
json::stack::array server_keys_out
{
top, "server_keys"
};
for(const auto &[server_name, requests] : server_keys_request)
{
if(empty(json::object(requests)))
{
keys::cache::for_each(server_name, [&server_keys_out]
(const m::keys &keys)
{
server_keys_out.append(keys.source);
return true;
});
continue;
}
for(const auto &[key_id, criteria] : json::object(requests))
{
const time_t &minimum_valid_until_ts
{
json::object(criteria).get<time_t>("minimum_valid_until_ts", ircd::time<milliseconds>())
};
keys::cache::get(server_name, key_id, [&server_keys_out, &minimum_valid_until_ts]
(const m::keys &keys)
{
// Condition ignored to match synapse behavior.
if((false) && json::get<"valid_until_ts"_>(keys) < minimum_valid_until_ts)
return;
server_keys_out.append(keys.source);
});
}
}
return {};
}
decltype(ircd::m::key_query_get)
ircd::m::key_query_get
{
key_query_resource, "GET", handle_key_query_get
};
ircd::m::resource::response
ircd::m::handle_key_query_get(client &client,
const m::resource::request &request)
{
if(request.parv.size() < 1)
throw m::NEED_MORE_PARAMS
{
"serverName path parameter required"
};
char server_name_buf[rfc3986::DOMAIN_BUFSIZE];
const auto server_name
{
url::decode(server_name_buf, request.parv[0])
};
char key_id_buf[64];
const auto key_id
{
request.parv.size() > 1?
url::decode(key_id_buf, request.parv[1]):
string_view{}
};
const time_t minimum_valid_until_ts
{
request.query.get<time_t>("minimum_valid_until_ts", ircd::time<milliseconds>())
};
if(key_id)
{
const auto respond{[&client]
(const json::object &keys)
{
resource::response
{
client, keys
};
}};
if(!keys::cache::get(server_name, key_id, respond))
throw m::NOT_FOUND
{
"Key '%s' from server '%s' is not cached by this server",
key_id,
server_name,
};
return {}; // responded from closure
}
resource::response::chunked response
{
client, http::OK
};
json::stack out
{
response.buf, response.flusher()
};
json::stack::object top{out};
json::stack::array server_keys
{
top, "server_keys"
};
keys::cache::for_each(server_name, [&server_keys, &minimum_valid_until_ts]
(const m::keys &keys)
{
// Condition ignored to match synapse behavior.
if((false) && json::get<"valid_until_ts"_>(keys) < minimum_valid_until_ts)
return true;
server_keys.append(keys.source);
return true;
});
return {};
}